library(beeswarm)
library(naniar)
library(zoo)

Attaching package: ‘zoo’

The following objects are masked from ‘package:base’:

    as.Date, as.Date.numeric
# install.packages("zoo")
library(janitor)

Attaching package: ‘janitor’

The following objects are masked from ‘package:stats’:

    chisq.test, fisher.test
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
# install.packages("GGally")
# library(sets)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ──────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ ggplot2 3.3.3     ✓ purrr   0.3.4
✓ tibble  3.0.6     ✓ stringr 1.4.0
✓ tidyr   1.1.2     ✓ forcats 0.5.1
✓ readr   1.4.0     
── Conflicts ─────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(ggplot2)
library(GGally) # for ggpairs
Registered S3 method overwritten by 'GGally':
  method from   
  +.gg   ggplot2
library(lubridate)

Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
# install.packages("maps")
# library(maps)
load_file <- function(file_path){
  read_csv(file_path)
}

tx_data <- load_file("./../data/COVID-19_cases_TX.csv")

── Column specification ─────────────────────────────────────────────────────────────────────────────────────────
cols(
  county_fips_code = col_character(),
  county_name = col_character(),
  state = col_character(),
  state_fips_code = col_double(),
  date = col_date(format = ""),
  confirmed_cases = col_double(),
  deaths = col_double()
)
global_mobility_report <- load_file("./../data/Global_Mobility_Report.csv")

── Column specification ─────────────────────────────────────────────────────────────────────────────────────────
cols(
  country_region_code = col_character(),
  country_region = col_character(),
  sub_region_1 = col_character(),
  sub_region_2 = col_logical(),
  metro_area = col_logical(),
  iso_3166_2_code = col_character(),
  census_fips_code = col_logical(),
  date = col_date(format = ""),
  retail_and_recreation_percent_change_from_baseline = col_double(),
  grocery_and_pharmacy_percent_change_from_baseline = col_double(),
  parks_percent_change_from_baseline = col_double(),
  transit_stations_percent_change_from_baseline = col_double(),
  workplaces_percent_change_from_baseline = col_double(),
  residential_percent_change_from_baseline = col_double()
)

4199216 parsing failures.
 row        col           expected                  actual                                   file
3036 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
3037 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
3038 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
3039 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
3040 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
.... .......... .................. ....................... ......................................
See problems(...) for more details.
# cases_plus_census <- load_file("./../data/COVID-19_cases_plus_census.csv")
cols_keep <- c("county_fips_code", "confirmed_cases", "deaths", "median_income", "male_pop", "female_pop", "total_pop", "median_age", "worked_at_home", "male_65_to_66", "male_67_to_69", 
               "male_70_to_74", "male_75_to_79", "male_80_to_84",
               "male_85_and_over", "female_65_to_66", "female_67_to_69", 
               "female_70_to_74", "female_75_to_79", "female_80_to_84",
               "female_85_and_over")
subset_census <- cases_plus_census[cols_keep]

subset_census$male_elderly_pop <- subset_census %>% select(c("male_65_to_66",
                                                             "male_67_to_69", 
                                                             "male_70_to_74",
                                                             "male_75_to_79",
                                                             "male_80_to_84",
                                                             "male_85_and_over")
                                                           ) %>% rowSums()

subset_census$female_elderly_pop <- subset_census %>% select(c("female_65_to_66",
                                                             "female_67_to_69", 
                                                             "female_70_to_74",
                                                             "female_75_to_79",
                                                             "female_80_to_84",
                                                             "female_85_and_over")
                                                           ) %>% rowSums()

cols_keep <- c("county_fips_code", "confirmed_cases", "deaths", "median_income",
               "male_pop", "female_pop", "total_pop", "median_age",
               "worked_at_home", "male_elderly_pop", "female_elderly_pop")
subset_census <- subset_census[cols_keep]
subset_census

# cols_keep <- c("date", "retail_and_recreation_percent_change_from_baseline", "grocery_and_pharmacy_percent_change_from_baseline", "parks_percent_change_from_baseline", "transit_stations_percent_change_from_baseline", "workplaces_percent_change_from_baseline", "residential_percent_change_from_baseline")
# subset_mobility <- global_mobility_report[cols_keep]
# glo
# subset_mobility$date <- as.Date(subset_mobility$date, format="%Y-%m-%d")

Data Understanding

Missing values

# global_mobility_report %>% filter(is.na(sub_region_1)) %>% select(country_region) %>%
#   unique()

# global_mobility_report %>% filter(is.na(sub_region_1)) %>% select(country_region) %>%
#   unique()
# global_mobility_report

# global_mobility_report %>% filter(is.na(sub_region_1)) %>% filter(country_region == "Ghana") %>%
#   select(country_region_code, date) %>% arrange(date)

# global_mobility_report %>% filter(is.na(sub_region_1)) %>%
#   # filter(country_region_code == "US") %>% select(date) %>%
# group_by(country_region, date) %>% select(date, country_region) %>%
# filter(n()>1) %>% summarize(n=n()) %>% filter(country_region == "Ghana")
bad_cols <- c("sub_region_2", "metro_area", "iso_3166_2_code", "census_fips_code")
global_mobility_report <- global_mobility_report %>% 
  filter(!is.na(sub_region_1)) %>% 
  group_by(country_region, date) %>%
  arrange(country_region, sub_region_1, date) %>% 
  select(-one_of(bad_cols))
  # select(country_region_code, sub_region_1, date) %>%
  # unique()
global_mobility_report
# global_mobility_report
vis_miss(global_mobility_report, sort_miss = T, warn_large_data= F)

vis_miss(tx_data, sort_miss = T, warn_large_data= F)

vis_miss(subset_census, sort_miss = T, warn_large_data = F)

Duplicate Data

get_dupes(load_file("./../data/Global_Mobility_Report.csv"))

── Column specification ─────────────────────────────────────────────────────────────────────────────────────────
cols(
  country_region_code = col_character(),
  country_region = col_character(),
  sub_region_1 = col_character(),
  sub_region_2 = col_logical(),
  metro_area = col_logical(),
  iso_3166_2_code = col_character(),
  census_fips_code = col_logical(),
  date = col_date(format = ""),
  retail_and_recreation_percent_change_from_baseline = col_double(),
  grocery_and_pharmacy_percent_change_from_baseline = col_double(),
  parks_percent_change_from_baseline = col_double(),
  transit_stations_percent_change_from_baseline = col_double(),
  workplaces_percent_change_from_baseline = col_double(),
  residential_percent_change_from_baseline = col_double()
)

4199216 parsing failures.
 row        col           expected                  actual                                   file
3036 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
3037 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
3038 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
3039 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
3040 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
.... .......... .................. ....................... ......................................
See problems(...) for more details.
No variable names specified - using all columns.
# global_mobility_report[duplicated(global_mobility_report)]
mobility_dupes <- get_dupes(global_mobility_report)
No variable names specified - using all columns.
census_dupes <- get_dupes(subset_census)
No variable names specified - using all columns.

No duplicate combinations found of: county_fips_code, confirmed_cases, deaths, median_income, male_pop, female_pop, total_pop, median_age, worked_at_home, ... and 5 other variables
tx_dupes <- get_dupes(tx_data)
No variable names specified - using all columns.

No duplicate combinations found of: county_fips_code, county_name, state, state_fips_code, date, confirmed_cases, deaths
mobility_dupes
census_dupes
tx_dupes
mobility_dupes %>% ungroup()
mobility_dupes %>% ungroup() %>% filter(country_region == "United States")

Graphs

library(RColorBrewer)
plot_vs_county <- function(df, col_val, percentile=FALSE,
                           fips_title="county_fips_code", banks=6, 
                           legend_title="", graphic_title=""){
  # Subset for speed 
  df <- df[c(fips_title, col_val)]
  
  # Get county data
  gcounty <- ggplot2::map_data("county")
  # USA map data
  gusa <- map_data("state")
  
  if (banks > 9){
    mycolors <- colorRampPalette(brewer.pal(9, "Reds"))(banks)
  }
  
  # Format with subregions
  fipstab <-
      transmute(maps::county.fips, fips, county = sub(":.*", "", polyname)) %>%
      unique() %>%
      separate(county, c("region", "subregion"), sep = ",")
  
  # Combine in desired order (NA for missing)
  gcounty <- left_join(gcounty, fipstab, c("region", "subregion"))


  dis <- df
  dis$rprop <- rank(df[col_val])
  dis$pcls <- cut(100 * percent_rank(df[col_val]), seq(0, 100, len = banks),
                        include.lowest = TRUE)

  # Missing data
  anti_join(gcounty, dis, by = c("fips" = fips_title)) %>%
    select(region, subregion) %>%
    unique()
  gcounty_pop <- left_join(gcounty, dis, by = c("fips" = fips_title))
  fill_vals <- gcounty_pop[col_val]

  # Plot
  if (legend_title == ""){
    legend_title <- col_val
  }

  if (percentile == FALSE){
    # names(gcounty_pop)[names(gcounty_pop) == col_val] <- "col_of_interest"
    plt <- ggplot(gcounty_pop) +
      geom_polygon(aes(long, lat, group = group, fill = get(col_val)),
                   color = "grey", size = 0.1, name="Percent Infected") +
      geom_polygon(aes(long, lat, group = group),
                   fill = NA, data = gusa, color = "lightgrey") +
      coord_map("bonne", parameters = 41.6) + ggthemes::theme_map()+
      scale_fill_gradient2()
       # scale_fill_gradient(low = "white", high = "red", na.value = "grey")
      # scale_fill_gradientn(colours = terrain.colors(10))
  }

  if (percentile == TRUE){
    plt <- ggplot(gcounty_pop) +
      geom_polygon(aes(long, lat, group = group, fill = pcls),
                   color = "grey", size = 0.1) +
      geom_polygon(aes(long, lat, group = group),
                   fill = NA, data = gusa, color = "lightgrey") +
      coord_map("bonne", parameters = 41.6) + ggthemes::theme_map() +
      scale_fill_manual(values = mycolors, na.value = "grey") +
      # scale_fill_brewer(palette = "viridis", na.value = "grey") +
      theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
            legend.background = element_rect(fill = NA), 
            legend.position = "left")
  }
  plt <- plt + labs(fill=legend_title) + ggtitle(graphic_title)
  plt
}
subset_census
subset_census['pct_infected'] <- subset_census['confirmed_cases']/subset_census['total_pop']
subset_census['pct_deaths'] <- subset_census['deaths']/subset_census['total_pop']
subset_census$death_rate <- subset_census$deaths/subset_census$confirmed_cases
subset_census$county_fips_code <-as.integer(subset_census$county_fips_code)
subset_census$elderly_pop <- subset_census$male_elderly_pop + subset_census$female_elderly_pop
subset_census$pct_elderly <- subset_census$elderly_pop/subset_census$total_pop
subset_census
plot_vs_county(subset_census, "pct_infected", legend_title = "Percent Infected")
Ignoring unknown parameters: name

plot_vs_county(subset_census, "pct_infected", percentile = TRUE, banks=11, 
               legend_title = "Percentile Infected",
               graphic_title = "Percentile of Percentage of People Infected by County")

plot_vs_county(subset_census, "pct_deaths", percentile = TRUE, banks=11, 
               legend_title = "Percentile Deaths",
               graphic_title = "Percentile of Percentage of Deaths by County")

plot_vs_county(subset_census, "death_rate", percentile = TRUE, banks=11, 
               legend_title = "Percentile Mortality Rate",
               graphic_title = "Percentile of Mortality Rate by County")

plot_vs_county(subset_census, "death_rate", 
               legend_title = "Percentile Mortality Rate",
               graphic_title = "Percentile of Mortality Rate by County")
Ignoring unknown parameters: name

normed_census_attributes
plot_vs_county(subset_census, "total_pop", 
               percentile = T,
               banks = 11,
               legend_title = "Percentile",
               graphic_title = "Population Density by County")

plot_vs_county(subset_census, "median_income", 
               percentile = T,
               banks = 11,
               legend_title = "Percentile of Median Income",
               graphic_title = "Median Income by County")

plot_vs_county(normed_census_attributes %>% 
                 mutate(county_fips_code = subset_census$county_fips_code),
               "pct_elderly", 
               percentile = T,
               banks = 11,
               legend_title = "Percentile of Elderly Population",
               graphic_title = "Elderly Population by County")

census_corr_cols <- colnames(subset_census)
census_corr_cols <- census_corr_cols[-1]
census_corr_cols
 [1] "confirmed_cases"    "deaths"             "median_income"      "male_pop"           "female_pop"        
 [6] "total_pop"          "median_age"         "worked_at_home"     "male_elderly_pop"   "female_elderly_pop"
[11] "pct_infected"       "pct_deaths"         "death_rate"         "elderly_pop"        "pct_elderly"       
subset_census
keep_cols <- c("confirmed_cases", "deaths", "median_income", "male_pop", "female_pop", "total_pop", "median_age", "worked_at_home", "male_65_to_66", "male_67_to_69", 
               "male_70_to_74", "male_75_to_79", "male_80_to_84",
               "male_85_and_over", "female_65_to_66", "female_67_to_69", 
               "female_70_to_74", "female_75_to_79", "female_80_to_84",
               "female_85_and_over")
ggcorr(cases_plus_census[keep_cols], 
       low="red", mid="grey", high="blue", hjust= 1, size=3, 
       label = TRUE, label_size = 3, label_color = "white", layout.exp = 4) +
  ggplot2::labs(title = "Pearson Correlation of Important Variables in the U.S. Census")

ggsave("./../imgs/small_census_pearson.png")
Saving 7.29 x 4.51 in image

# keep_cols <- c("county_fips_code", "confirmed_cases", "deaths", "median_income", "male_pop", "female_pop", "total_pop", "median_age", "worked_at_home", "male_65_to_66", "male_67_to_69", 
#                "male_70_to_74", "male_75_to_79", "male_80_to_84",
#                "male_85_and_over", "female_65_to_66", "female_67_to_69", 
#                "female_70_to_74", "female_75_to_79", "female_80_to_84",
#                "female_85_and_over")
keep_cols <- c("county_fips_code", "confirmed_cases", "deaths", "median_income", "male_pop", "female_pop", "total_pop", "median_age", "worked_at_home", "male_65_to_66", "male_67_to_69", 
               "male_70_to_74", "male_75_to_79", "male_80_to_84",
               "male_85_and_over", "female_65_to_66", "female_67_to_69", 
               "female_70_to_74", "female_75_to_79", "female_80_to_84",
               "female_85_and_over")

group_keeps <- list(c("county_fips_code", "confirmed_cases"), 
                    c("county_fips_code", "deaths"),
                    c("county_fips_code", "median_income"),
                    c("county_fips_code", "male_pop", "female_pop", "total_pop"),
                    c("county_fips_code", "median_age"), 
                    c("county_fips_code", "male_65_to_66", "male_67_to_69", 
               "male_70_to_74", "male_75_to_79", "male_80_to_84",
               "male_85_and_over", "female_65_to_66", "female_67_to_69", 
               "female_70_to_74", "female_75_to_79", "female_80_to_84",
               "female_85_and_over"))

# for (keep_col in group_keeps) {
#   plt <- cases_plus_census[keep_col] %>% 
#     pivot_longer(!county_fips_code, names_to = "Variable", values_to = "value") %>%
#     select(Variable, value) %>%
#     ggplot(aes(x=Variable, y=value, fill=Variable)) +
#       geom_boxplot() +
#       # scale_fill_viridis(discrete = TRUE, alpha=0.6, option="A") +
#       # theme_ipsum() +
#       # theme(
#       #   legend.position="none",
#       #   plot.title = element_text(size=11)
#       # ) +
#       ggtitle("Violin chart") +
#       geom_jitter(size=.5)+
#       xlab("")
#   print(plt)
#   
# }

# ones_to_look_at <- c("county_fips_code", "male_65_to_66", "male_67_to_69", 
#                "male_70_to_74", "male_75_to_79", "male_80_to_84",
#                "male_85_and_over", "female_65_to_66", "female_67_to_69", 
#                "female_70_to_74", "female_75_to_79", "female_80_to_84",
#                "female_85_and_over")
# plt <- cases_plus_census[ones_to_look_at] %>% 
#     pivot_longer(!county_fips_code, names_to = "Variable", values_to = "value") %>%
#     select(Variable, value) %>%
#     ggplot(aes(x=Variable, y=value, fill=Variable, layout.exp =20 )) +
#       geom_boxplot(layout.exp = 20) +
#       # scale_fill_viridis(discrete = TRUE, alpha=0.6, option="A") +
#       # theme_ipsum() +
#       # theme(
#       #   legend.position="none",
#       #   plot.title = element_text(size=11)
#       # ) +
#       ggtitle("Violin chart") +
#       # geom_jitter(size=.5)+
#       xlab("")
#   print(plt)

keep_cols <- c("county_fips_code", "confirmed_cases", "deaths", "median_income", "median_age", "worked_at_home")

plt <- cases_plus_census[keep_cols] %>% 
    pivot_longer(!county_fips_code, names_to = "Variable", values_to = "value") %>%
    select(Variable, value) %>%
  ggplot(
    aes(x=Variable, y=value, fill=Variable))+
  geom_boxplot()+
  #   aes(x=value, color=Variable, fill=Variable))+
  # geom_histogram()+
  
    # aes(x=Variable, y=value, fill=Variable))+
  # geom_violin()+

  theme(axis.text.x = element_text(size=6))+
  # xlab("Population") +
  # ylab("Assigned Probability (%)") +
  facet_wrap(~Variable)
plt

# ones_to_look_at <- c("county_fips_code", "male_65_to_66", "male_67_to_69",
#                "male_70_to_74", "male_75_to_79", "male_80_to_84",
#                "male_85_and_over", "female_65_to_66", "female_67_to_69",
#                "female_70_to_74", "female_75_to_79", "female_80_to_84",
#                "female_85_and_over")
# ones_to_look_at <- c("county_fips_code", "male_65_to_66", "male_67_to_69")
plt <- cases_plus_census[ones_to_look_at] %>% 
  pivot_longer(!county_fips_code, names_to = "Variable", values_to = "value") %>%
  select(Variable, value) %>%
#   gather(Variable, value, -county_fips_code) %>%
#     ggplot(aes(value, fill = Variable)) + geom_histogram() + facet_wrap(~county_fips_code)
# 
# plt

  ggplot( aes(x=value, color=Variable, fill=Variable)) +
      geom_histogram(alpha=0.6, binwidth = 5) +
      # scale_fill_viridis(discrete=TRUE) +
      # scale_color_viridis(discrete=TRUE) +
      # theme_ipsum() +
      # theme(
      #   legend.position="none",
      #   panel.spacing = unit(0.1, "lines"),
      #   strip.text.x = element_text(size = 8)
      # ) +
      theme(axis.text.x = element_text(size=6))+
      xlab("Population") +
      ylab("Assigned Probability (%)") +
      facet_wrap(~Variable)

plt

# png("./test.png", width=800, height = 800)
census_corr_cols <- colnames(subset_census)
census_corr_cols <- census_corr_cols[-1]
normed_census_attributes <- subset_census[census_corr_cols] %>%
  mutate(pct_female_elderly = female_elderly_pop/total_pop,
         pct_male_elderly = male_elderly_pop/total_pop,
         pct_worked_at_home = worked_at_home/total_pop,
         pct_female_pop = female_pop/total_pop,
         pct_male_pop = male_pop/total_pop) %>%
  rename(mortality_rate = death_rate) %>%
  select(mortality_rate, pct_deaths, pct_infected, pct_elderly,
         pct_female_elderly, pct_male_elderly, pct_female_pop, pct_male_pop,
         pct_worked_at_home, median_age, median_income)
  
ggcorr(normed_census_attributes, low="red", mid="grey", high="blue", hjust= .9, size=3, 
       label = TRUE, label_size = 3, label_color = "white", layout.exp = 3) +
  ggplot2::labs(title = "Pearson Correlation of Important Variables in the U.S. Census")

ggsave("./../imgs/census_pearson.png")
Saving 7.29 x 4.51 in image

# dev.off()
global_mobility_report
country_date_pct_change <- global_mobility_report %>% select(country_region_code
                                                             | contains("date") 
                                                             | contains("percent"))
Adding missing grouping variables: `country_region`
country_date_pct_change
coi_downsampled <- country_date_pct_change %>% filter(country_region_code %in% 
                                                        c("US", "CA", "NZ", "AE", "CN", "DE", "JP")) %>% 
  filter(weekdays(date) == "Saturday") %>% group_by(country_region_code, date) %>% summarise_all(mean, na.rm = T) %>% arrange(country_region_code, date)
argument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NA
coi_downsampled
interested_cols <- c("retail_and_recreation_percent_change_from_baseline",
                     "grocery_and_pharmacy_percent_change_from_baseline",
                     "parks_percent_change_from_baseline",
                     "transit_stations_percent_change_from_baseline",
                     "workplaces_percent_change_from_baseline",
                     "residential_percent_change_from_baseline")

col_labels <- c("Average Retail and Recreation Percent Change from Baseline",
                     "Average Grocery and Pharmacy Percent Change from Baseline",
                     "Average Parks Percent Change from Baseline",
                     "Average Transit Stations Percent Change from Baseline",
                     "Average Workplaces Percent Change from Baseline",
                     "Average Residential Percent Change from Baseline")


for (i in 1:length(col_labels)){
  print(i)
  plt <- ggplot(coi_downsampled,
       aes(x=date, y=get(interested_cols[i]), group=country_region_code,
                            color=country_region_code))+
  geom_point(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)), size=.5)+
  geom_line(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)))+
  # geom_point(size=.5)+geom_line()+
  labs(y = col_labels[i], x = "Date", color = "Country")+
  theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
        axis.title.y = element_text(size = 8))+
    ggplot2::labs(title = paste("Saturday", col_labels[i], sep=" "))
  save_path <- paste(c("./../imgs/", interested_cols[i], ".png"), collapse = "")
  ggsave(save_path)
  print(plt)
}
[1] 1
Saving 7 x 7 in image
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6

# ggplot(coi_downsampled,
#        aes(x=date, y=grocery_and_pharmacy_percent_change_from_baseline, group=country_region_code,
#                             color=country_region_code))+
  # geom_point(aes(y=rollmean(retail_and_recreation_percent_change_from_baseline, k=10, na.pad=TRUE)), size=.5)+
#   geom_line(aes(y=rollmean(retail_and_recreation_percent_change_from_baseline, k=10, na.pad=TRUE)))+
#   # geom_point(size=.5)+geom_line()+
#   labs(y = "Average Grocery and Pharmacy Percent Change from Baseline", x = "Date", color = "Country")+
#   theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
#         axis.title.y = element_text(size = 8))
#   # geom_line()
tx_county_data <- tx_data %>% filter(county_name != "Statewide Unallocated")
tx_total_state_data <- tx_data %>% filter(county_name == "Statewide Unallocated")
tx_total_state_data$cumulative_deaths <- cumsum(tx_total_state_data$deaths)
tx_total_state_data$cumulative_cases <- cumsum(tx_total_state_data$confirmed_cases)
tx_county_data
tx_total_state_data
col_labels <- c("Average Retail and Recreation Percent Change from Baseline",
                     "Average Grocery and Pharmacy Percent Change from Baseline",
                     "Average Parks Percent Change from Baseline",
                     "Average Transit Stations Percent Change from Baseline",
                     "Average Workplaces Percent Change from Baseline",
                     "Average Residential Percent Change from Baseline")
paste("Mondays", col_labels[1], sep=" ")
[1] "Mondays Average Retail and Recreation Percent Change from Baseline"

Since the above doesn’t really make sense (only 78 confirmed cases with over a thousand deaths), I am going to analyze on a per county basis and maybe that data will be more clear.

tx_by_day_based_on_county <- tx_county_data %>% 
  select(date, confirmed_cases, deaths) %>%
  group_by(date) %>% 
  summarise_all(sum, na.rm = T) %>%
  arrange(date)

# interested_cols <- c("confirmed_cases", "deaths")
# col_labels <- c("Total Cases", "Total Deaths")
# 
# for (i in 1:length(col_labels)){
#   print(i)
#   title <- paste(c("Texas ", col_labels[i]), collapse = "")
#   plt <- ggplot(tx_by_day_based_on_county,
#        aes(x=date, y=get(interested_cols[i])))+
#   # geom_point(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)), size=.5)+
#   # geom_line(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)))+
#   # geom_point(size=.5)+geom_line()+
#     geom_line(color)+
#   labs(y = col_labels[i], x = "Date", title = title)
#   # theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
#   #       axis.title.y = element_text(size = 8))
#   # save_path <- paste(c("./../imgs/", interested_cols[i], ".png"), collapse = "")
#   # ggsave(save_path)
#   print(plt)
# }
tx_by_day_based_on_county
install.packages("ggrepel")
trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/ggrepel_0.9.1.tgz'
Content type 'application/x-gzip' length 702306 bytes (685 KB)
==================================================
downloaded 685 KB

The downloaded binary packages are in
    /var/folders/2t/zk2m3vcj2_51x1r2p3cbnt9r0000gn/T//RtmpNDvNE3/downloaded_packages
library(ggrepel)
tx_by_day_based_on_county %>% pivot_longer(!date, names_to = "type", values_to = "count")
# t <- tibble("Max" = c(34378, 2248927), "date" = c("2021-01-25", "2021-01-25"),
#             "type" = c("deaths", "confirmed_cases"))
# t$date <- as.Date(t$date)
# t 

data_ends <- tx_by_day_based_on_county %>% pivot_longer(!date, names_to = "type", values_to = "count") %>% 
  group_by(type) %>% 
  top_n(1, count) 
data_ends
NA
library(scales)
# png("./../imgs/texas_covid_cases_total.png", width = 800, height = 800)
# tx_by_day_based_on_county %>% pivot_longer(!date, names_to = "type", values_to = "count")
ggplot(tx_by_day_based_on_county %>% pivot_longer(!date, names_to = "type", values_to = "count"),
       aes(x=date, y=count, group=type))+
         geom_line(aes(color=type))+
  # scale_y_continuous(trans = "log10",
  #                    labels = trans_breaks('log10', math_format(10^.x)))+
  scale_color_manual(labels = c("Confirmed Cases", "Deaths"), values = c("confirmed_cases"="blue",
                                                                         "deaths"="red"))+
  labs(y = "Total Persons", x = "Date", color = "")+
  geom_text_repel(aes(label = count), data = data_ends, size=3)+
  # scale_y_continuous(sec.axis = sec_axis(~ ., breaks = data_ends))+
  theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)))+
  ggtitle("Texas COVID-19 Cases")
  
# plt+ 
# ggplot(t, 
#              aes(x=Date, y= Max))+
#   geom_point()
# plt + geom_text_repel(aes(label = Max), data = t, fontface="plain", color="black",
#                   size=3)
# dev.off()

ggsave("./../imgs/texas_covid_cases_total.png")
Saving 7.29 x 4.51 in image

  # scale_y_log10()
         # labs(y = "Total Persons", x = "Date"))

# )
# 
# plt <- ggplot(coi_downsampled,
#        aes(x=date, y=get(interested_cols[i]), group=country_region_code,
#                             color=country_region_code))+
#   geom_point(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)), size=.5)+
#   geom_line(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)))+
#   # geom_point(size=.5)+geom_line()+
#   labs(y = col_labels[i], x = "Date", color = "Country")+
#   theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
#         axis.title.y = element_text(size = 8))
#   save_path <- paste(c("./../imgs/", interested_cols[i], ".png"), collapse = "")
#   ggsave(save_path)
#   print(plt)
tx_county_data
subset_census

tx_state <- map_data("state") %>% subset(region == "texas")
tx_county_map_data <- map_data("county") %>% subset(region == "texas")

tx_state
tx_county_map_data

gcounty <- map_data("county")
# 
# fipstab <-
#       transmute(maps::county.fips, fips, county = sub(":.*", "", polyname)) %>%
#       unique() %>%
#       separate(county, c("region", "subregion"), sep = ",")

# Format with subregions
fipstab <-
  transmute(maps::county.fips, fips, county = sub(":.*", "", polyname)) %>%
  unique() %>%
  separate(county, c("region", "subregion"), sep = ",")
  
  # # Combine in desired order (NA for missing)
  # gcounty <- left_join(gcounty, fipstab, c("region", "subregion"))


tx_geo_data <- left_join(gcounty, fipstab, c("region", "subregion")) %>%
  left_join(subset_census, c("fips" = "county_fips_code")) %>% filter(region == "texas") %>%
  unique()

tx_geo_data$dinfect_pcls <- cut(100 * percent_rank(tx_geo_data$pct_infected), seq(0, 100, len = 11),
                        include.lowest = TRUE)
tx_geo_data$deaths_pcls <- cut(100 * percent_rank(tx_geo_data$pct_deaths), seq(0, 100, len = 11),
                        include.lowest = TRUE)
tx_geo_data$death_rate_pcls <- cut(100 * percent_rank(tx_geo_data$death_rate), seq(0, 100, len = 11),
                        include.lowest = TRUE)

tx_geo_data


# 
# # Lowercase
# tx_county_data$county_name <- tolower(tx_county_data$county_name)
# 
# # Remove ' county'
# tx_county_data$county_name <- sub("\\s*county\\b.*", "", tx_county_data$county_name)
# tx_county_data
# 
# # Get max confirmed cases and deaths
# tx_county_data
# 
# 
# # # Join the data with state geo info
# # tx_geo_data <- left_join(tx_county_map_data, tx_county_data, by = c("subregion" = "county_name"))
# # tx_geo_data

mycolors <- colorRampPalette(brewer.pal(9, "Reds"))(11)

ggplot(tx_geo_data)+
  coord_map() + ggthemes::theme_map()+
  geom_polygon(aes(long, lat, group = group, fill=death_rate_pcls))+
  scale_fill_manual(values = mycolors, na.value = "grey") +
  theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)), legend.position = "left")+
  #       legend.background = element_rect(fill = NA),
        # legend.position = "left")+
  labs(fill="Percentile") + ggtitle("Texas County Mortality Rate Percentiles")

ggsave("./../imgs/texas_county_mortality_percentiles.png")
Saving 7.29 x 4.51 in image

# ggplot(tx_geo_data) +
#       geom_polygon(aes(long, lat, group = group, fill = death_rate_pcls),
#                    color = "grey", size = 0.1) +
#       # geom_polygon(aes(long, lat, group = group),
#       #              fill = NA, data = gusa, color = "lightgrey") +
#       coord_map("bonne", parameters = 41.6) + ggthemes::theme_map() +
#       scale_fill_manual(values = mycolors, na.value = "grey") +
#       # scale_fill_brewer(palette = "viridis", na.value = "grey") +
#       theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
#             legend.background = element_rect(fill = NA),
#             legend.position = "left")



# if (percentile == TRUE){
#     plt <- ggplot(gcounty_pop) +
#       geom_polygon(aes(long, lat, group = group, fill = pcls),
#                    color = "grey", size = 0.1) +
#       geom_polygon(aes(long, lat, group = group),
#                    fill = NA, data = gusa, color = "lightgrey") +
#       coord_map("bonne", parameters = 41.6) + ggthemes::theme_map() +
#       scale_fill_manual(values = mycolors, na.value = "grey") +
#       # scale_fill_brewer(palette = "viridis", na.value = "grey") +
#       theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
#             legend.background = element_rect(fill = NA), 
#             legend.position = "left")
    

# plt <- ggplot(gcounty_pop) +
#       geom_polygon(aes(long, lat, group = group, fill = dinfect_pcls),
#                    color = "grey", size = 0.1) +
#       geom_polygon(aes(long, lat, group = group),
#                    fill = NA, data = gusa, color = "lightgrey") +
#       coord_map("bonne", parameters = 41.6) + ggthemes::theme_map() +
#       scale_fill_manual(values = mycolors, na.value = "grey") +
#       # scale_fill_brewer(palette = "viridis", na.value = "grey") +
#       theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
#             legend.background = element_rect(fill = NA),
#             legend.position = "left")

# ggplot(tx_geo_data) +
#          coord_map() + 
#   ggthemes::theme_map()+
#   geom_polygon(aes(long, lat, group = subregion, fill = confirmed_cases))
# pc_cont_iowa <- geom_polygon(aes(long, lat, group = group, fill = pchange),
#                              color = "grey", size = 0.2)
data_ends <- dallas_data %>% pivot_longer(!date, names_to = "type", values_to = "count") %>% 
  group_by(type) %>% 
  top_n(1, count) 
data_ends
# dallas_data <- tx_county_data %>% filter(county_name == "dallas") 
dallas_data <- tx_county_data %>% filter(county_name == "Dallas County") %>% 
  select(date, confirmed_cases, deaths)

data_ends <- dallas_data %>% pivot_longer(!date, names_to = "type", values_to = "count") %>% 
  group_by(type) %>% 
  top_n(1, count) 

ggplot(dallas_data %>% pivot_longer(!date, names_to = "type", values_to = "count"),
       aes(x=date, y=count, group=type))+
         geom_line(aes(color=type))+
  # scale_y_continuous(trans = "log10", labels = trans_breaks("log10", math_format(10^.x)))+
  # scale_y_log10(breaks=c(100, 300, 500, 1000, 3000, 5000, 10000, 30000, 50000, 100000, 300000),
  #               labels=c('100', '300', '500', '1000', '3000', '5000', '10000', '30000', '50000', '100000', '300000'))+
  scale_color_manual(labels = c("Confirmed Cases", "Deaths"), values = c("confirmed_cases"="blue",
                                                                         "deaths"="red"))+
  labs(y = "Total Persons", x = "Date", color = "")+
  geom_text_repel(aes(label = count), data = data_ends, size=3)+
  theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)))+
  ggtitle("Dallas COVID-19 Cases")
  ggsave("./../imgs/dallas_covid_cases_total.png")
Saving 7.29 x 4.51 in image

sgcounty <- map_data("state")

# Format with subregions
fipstab <-
  transmute(maps::county.fips, fips, county = sub(":.*", "", polyname)) %>%
  unique() %>%
  separate(county, c("region", "subregion"), sep = ",")

us_geo_data <- left_join(gcounty, fipstab, c("region", "subregion")) %>%
  left_join(subset_census, c("fips" = "county_fips_code")) %>%
  unique() %>% select(long, lat, region, subregion, group, confirmed_cases, deaths, median_income, 
                      male_pop, female_pop, total_pop, median_age,
                      worked_at_home)
# us_geo_data

# Get the total cases by state
state_data_breakdown <- us_geo_data %>% 
  drop_na() %>% select(region, subregion, confirmed_cases, deaths, median_income, 
                      male_pop, female_pop, total_pop, median_age,
                      worked_at_home) %>% unique() %>%
  group_by(region) %>% select_if(is.numeric) %>%
  summarise_all(sum)

state_data_breakdown$pct_deaths <- state_data_breakdown$deaths/state_data_breakdown$total_pop
state_data_breakdown$pct_infect <- state_data_breakdown$confirmed_cases/state_data_breakdown$total_pop
state_data_breakdown$death_rate <- state_data_breakdown$deaths/state_data_breakdown$confirmed_cases

print(state_data_breakdown %>% arrange(death_rate, decreasing=T))

state_geo_data <- us_geo_data %>% select(long, lat, region, group) %>% left_join(state_data_breakdown,
                                                        by = "region")

state_geo_data

# ggplot(tx_by_day_based_on_county %>% pivot_longer(!date, names_to = "type", values_to = "count"),
#        aes(x=date, y=count, group=type, color = type))+
#          geom_line()+
#   scale_y_continuous(trans = "log10",
#                      labels = trans_breaks('log10', math_format(10^.x)))+
#   scale_color_manual(labels = c("Confirmed Cases", "Deaths"), values = c("confirmed_cases"="blue",
#                                                                          "deaths"="red"))+
#   labs(y = "Total Persons", x = "Date", color = "")+
#   theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)))+
#   ggtitle("US COVID-19 Cases")
  # ggsave("./../imgs/texas_covid_cases_total.png")
# state_geo_data$state_group <- factor
state_geo_data$state_group <- factor(state_geo_data$region) 
state_geo_data$state_group <- as.numeric(state_geo_data$state_group)
state_geo_data
state_data_breakdown %>% select(region, death_rate) %>% arrange(death_rate) 
# http://homepage.stat.uiowa.edu/~luke/classes/STAT4580-2020/maps.html

library(scales)
sp <- select(state_data_breakdown, region = region, death_rate)
gusa <- map_data("state")

gusa_pop <- left_join(gusa, sp, "region")
gusa_pop

ggplot(gusa_pop) +
    geom_polygon(aes(long, lat, group = group, fill = death_rate), color="grey") +
    coord_map("bonne", parameters = 41.6) +
    ggthemes::theme_map()+
  theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)))+
  scale_fill_gradient(labels = percent)+
  ggtitle("Mortality Rate by State")+
  labs(fill="Mortality Rate")

ggsave("./../imgs/mortality_rate_by_state.png")
Saving 7.29 x 4.51 in image

tx_data
cases_plus_census
tx_county_data
# Get the first occurrences of covid case after first tx case
tx_first_cases_by_county <- tx_county_data %>% filter(confirmed_cases > 0) %>% 
  group_by(county_name) %>%
  arrange(date) %>% slice_min(order_by = date, n = 1) %>% 
  select(county_fips_code, county_name, date)

first_day_in_tx <- min(tx_first_cases_by_county$date)

tx_first_cases_by_county <- tx_first_cases_by_county %>% 
  mutate(days_from_first_tx_case = date - first_day_in_tx) %>%
  mutate(county_fips_code = as.integer(county_fips_code))

tx_first_cases_by_county
tx_first_cases_by_county %>% filter(days_from_first_tx_case == time_length(0, "days"))
tx_state <- map_data("state") %>% subset(region == "texas")
tx_county_map_data <- map_data("county") %>% subset(region == "texas")

gcounty <- map_data("county")

# Format with subregions
fipstab <-
  transmute(maps::county.fips, fips, county = sub(":.*", "", polyname)) %>%
  unique() %>%
  separate(county, c("region", "subregion"), sep = ",") %>% filter(region == "texas")


fipstab
tx_geo_days <- left_join(gcounty, fipstab, c("region", "subregion")) %>%
  left_join(tx_first_cases_by_county, c("fips" = "county_fips_code")) %>% filter(region == "texas") %>%
  unique()

tx_geo_days
# 
# tx_geo_data$dinfect_pcls <- cut(100 * percent_rank(tx_geo_data$pct_infected), seq(0, 100, len = 11),
#                         include.lowest = TRUE)
# tx_geo_data$deaths_pcls <- cut(100 * percent_rank(tx_geo_data$pct_deaths), seq(0, 100, len = 11),
#                         include.lowest = TRUE)
# tx_geo_data$death_rate_pcls <- cut(100 * percent_rank(tx_geo_data$death_rate), seq(0, 100, len = 11),
#                         include.lowest = TRUE)
# 
# tx_geo_data

# # Lowercase
# tx_county_data$county_name <- tolower(tx_county_data$county_name)
# 
# # Remove ' county'
# tx_county_data$county_name <- sub("\\s*county\\b.*", "", tx_county_data$county_name)
# tx_county_data
ggplot(tx_geo_days %>% mutate(days_from_first_tx_case = as.integer(days_from_first_tx_case))) +
  coord_map() + ggthemes::theme_map()+
  geom_polygon(aes(long, lat, group = group, fill=days_from_first_tx_case))+
  # scale_fill_manual(values = mycolors, na.value = "grey") +
  theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)), legend.position = "left")+
  #       legend.background = element_rect(fill = NA),
        # legend.position = "left")+
  labs(fill="Days from First TX Case") + ggtitle("Texas Spread of COVID-19")+
  # scale_fill_manual(low="red", mid="grey", high="blue")
  scale_fill_gradient(low = "grey", high = "red", na.value = NA)+
  geom_text(data=cnames, aes(long, lat, label=subregion), size=3)
ggsave("./../imgs/tx_spread_days.png")
Saving 7.29 x 4.51 in image

  # scale_fill_gradient(low="red", mid="grey", high="blue")
  # scale_fill_gradientn()
  # scale_colour_gradient2()
  
ggplot(tx_geo_data) +
  coord_map() + ggthemes::theme_map()+
  geom_polygon(aes(long, lat, group = group, fill=median_income))+
  # scale_fill_manual(values = mycolors, na.value = "grey") +
  theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)), legend.position = "left")+
  #       legend.background = element_rect(fill = NA),
        # legend.position = "left")+
  labs(fill="Days from First TX Case") + ggtitle("Texas Spread of COVID-19")+
  # scale_fill_manual(low="red", mid="grey", high="blue")
  scale_fill_gradient(low = "grey", high = "red", na.value = NA)

cnames <- aggregate(cbind(long, lat) ~ subregion, data=tx_county_map_data, 
                    FUN=function(x)mean(range(x)))

mycolors <- colorRampPalette(brewer.pal(9, "Reds"))(11)

ggplot(tx_geo_data)+
  coord_map() + ggthemes::theme_map()+
  geom_polygon(aes(long, lat, group = group, fill=death_rate_pcls))+
  scale_fill_manual(values = mycolors, na.value = "grey") +
  theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)), legend.position = "left")+
  #       legend.background = element_rect(fill = NA),
        # legend.position = "left")+
  labs(fill="Percentile") + ggtitle("Texas County Mortality Rate Percentiles")+
  geom_text(data=cnames, aes(long, lat, label = subregion), size=3)

# Get top 5 worst and best mortality rates counties
worst_counties <- tx_geo_data %>%
  select(subregion, pct_deaths) %>%
  distinct() %>%
  slice_max(pct_deaths, n=3) %>%
  select(subregion)

best_counties <- tx_geo_data %>%
  select(subregion, pct_deaths) %>%
  distinct() %>%
  slice_min(pct_deaths, n=3) %>%
  select(subregion)

worst_counties <- worst_counties$subregion
best_counties <- best_counties$subregion

worst_counties
[1] "motley" "lamb"   "cottle"
best_counties
[1] "borden" "king"   "loving"
my_counties <- c("harris", "dallas", "bexar", "travis", "collin")
cnames <- aggregate(cbind(long, lat) ~ subregion, data=tx_county_map_data,
                    FUN=function(x)mean(range(x))) %>%
  # filter(subregion %in% worst_counties | subregion %in% best_counties)
  filter(subregion %in% my_counties)

cnames

mycolors <- colorRampPalette(brewer.pal(9, "Reds"))(11)

ggplot(tx_geo_data)+
  coord_map() + ggthemes::theme_map()+
  geom_polygon(aes(long, lat, group = group, fill=death_rate_pcls))+
  scale_fill_manual(values = mycolors, na.value = "grey") +
  theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)), legend.position = "left")+
  #       legend.background = element_rect(fill = NA),
        # legend.position = "left")+
  labs(fill="Percentile") + ggtitle("Texas County Mortality Rate Percentiles")+
  geom_text(data=cnames, aes(long, lat, label=subregion), size=3)
  # geom_text(data=cnames, aes(long, lat, label = subregion), size=3)

ggsave("./../imgs/texas_county_mortality_percentiles.png")
Saving 7.29 x 4.51 in image

tx_county_data
subset_census %>% select_if(is.numeric) %>% summarise_all(mean)
LS0tCnRpdGxlOiAiQ2xlYW5lZCBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkoYmVlc3dhcm0pCmxpYnJhcnkobmFuaWFyKQpsaWJyYXJ5KHpvbykKIyBpbnN0YWxsLnBhY2thZ2VzKCJ6b28iKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkoZHBseXIpCiMgaW5zdGFsbC5wYWNrYWdlcygiR0dhbGx5IikKIyBsaWJyYXJ5KHNldHMpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoR0dhbGx5KSAjIGZvciBnZ3BhaXJzCmxpYnJhcnkobHVicmlkYXRlKQojIGluc3RhbGwucGFja2FnZXMoIm1hcHMiKQojIGxpYnJhcnkobWFwcykKYGBgCgpgYGB7cn0KbG9hZF9maWxlIDwtIGZ1bmN0aW9uKGZpbGVfcGF0aCl7CiAgcmVhZF9jc3YoZmlsZV9wYXRoKQp9Cgp0eF9kYXRhIDwtIGxvYWRfZmlsZSgiLi8uLi9kYXRhL0NPVklELTE5X2Nhc2VzX1RYLmNzdiIpCmdsb2JhbF9tb2JpbGl0eV9yZXBvcnQgPC0gbG9hZF9maWxlKCIuLy4uL2RhdGEvR2xvYmFsX01vYmlsaXR5X1JlcG9ydC5jc3YiKQojIGNhc2VzX3BsdXNfY2Vuc3VzIDwtIGxvYWRfZmlsZSgiLi8uLi9kYXRhL0NPVklELTE5X2Nhc2VzX3BsdXNfY2Vuc3VzLmNzdiIpCmBgYApgYGB7cn0KY29sc19rZWVwIDwtIGMoImNvdW50eV9maXBzX2NvZGUiLCAiY29uZmlybWVkX2Nhc2VzIiwgImRlYXRocyIsICJtZWRpYW5faW5jb21lIiwgIm1hbGVfcG9wIiwgImZlbWFsZV9wb3AiLCAidG90YWxfcG9wIiwgIm1lZGlhbl9hZ2UiLCAid29ya2VkX2F0X2hvbWUiLCAibWFsZV82NV90b182NiIsICJtYWxlXzY3X3RvXzY5IiwgCiAgICAgICAgICAgICAgICJtYWxlXzcwX3RvXzc0IiwgIm1hbGVfNzVfdG9fNzkiLCAibWFsZV84MF90b184NCIsCiAgICAgICAgICAgICAgICJtYWxlXzg1X2FuZF9vdmVyIiwgImZlbWFsZV82NV90b182NiIsICJmZW1hbGVfNjdfdG9fNjkiLCAKICAgICAgICAgICAgICAgImZlbWFsZV83MF90b183NCIsICJmZW1hbGVfNzVfdG9fNzkiLCAiZmVtYWxlXzgwX3RvXzg0IiwKICAgICAgICAgICAgICAgImZlbWFsZV84NV9hbmRfb3ZlciIpCnN1YnNldF9jZW5zdXMgPC0gY2FzZXNfcGx1c19jZW5zdXNbY29sc19rZWVwXQoKc3Vic2V0X2NlbnN1cyRtYWxlX2VsZGVybHlfcG9wIDwtIHN1YnNldF9jZW5zdXMgJT4lIHNlbGVjdChjKCJtYWxlXzY1X3RvXzY2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtYWxlXzY3X3RvXzY5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWFsZV83MF90b183NCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWFsZV83NV90b183OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWFsZV84MF90b184NCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWFsZV84NV9hbmRfb3ZlciIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUgcm93U3VtcygpCgpzdWJzZXRfY2Vuc3VzJGZlbWFsZV9lbGRlcmx5X3BvcCA8LSBzdWJzZXRfY2Vuc3VzICU+JSBzZWxlY3QoYygiZmVtYWxlXzY1X3RvXzY2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmZW1hbGVfNjdfdG9fNjkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmZW1hbGVfNzBfdG9fNzQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImZlbWFsZV83NV90b183OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZmVtYWxlXzgwX3RvXzg0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmZW1hbGVfODVfYW5kX292ZXIiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lIHJvd1N1bXMoKQoKY29sc19rZWVwIDwtIGMoImNvdW50eV9maXBzX2NvZGUiLCAiY29uZmlybWVkX2Nhc2VzIiwgImRlYXRocyIsICJtZWRpYW5faW5jb21lIiwKICAgICAgICAgICAgICAgIm1hbGVfcG9wIiwgImZlbWFsZV9wb3AiLCAidG90YWxfcG9wIiwgIm1lZGlhbl9hZ2UiLAogICAgICAgICAgICAgICAid29ya2VkX2F0X2hvbWUiLCAibWFsZV9lbGRlcmx5X3BvcCIsICJmZW1hbGVfZWxkZXJseV9wb3AiKQpzdWJzZXRfY2Vuc3VzIDwtIHN1YnNldF9jZW5zdXNbY29sc19rZWVwXQpzdWJzZXRfY2Vuc3VzCgojIGNvbHNfa2VlcCA8LSBjKCJkYXRlIiwgInJldGFpbF9hbmRfcmVjcmVhdGlvbl9wZXJjZW50X2NoYW5nZV9mcm9tX2Jhc2VsaW5lIiwgImdyb2NlcnlfYW5kX3BoYXJtYWN5X3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUiLCAicGFya3NfcGVyY2VudF9jaGFuZ2VfZnJvbV9iYXNlbGluZSIsICJ0cmFuc2l0X3N0YXRpb25zX3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUiLCAid29ya3BsYWNlc19wZXJjZW50X2NoYW5nZV9mcm9tX2Jhc2VsaW5lIiwgInJlc2lkZW50aWFsX3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUiKQojIHN1YnNldF9tb2JpbGl0eSA8LSBnbG9iYWxfbW9iaWxpdHlfcmVwb3J0W2NvbHNfa2VlcF0KIyBnbG8KIyBzdWJzZXRfbW9iaWxpdHkkZGF0ZSA8LSBhcy5EYXRlKHN1YnNldF9tb2JpbGl0eSRkYXRlLCBmb3JtYXQ9IiVZLSVtLSVkIikKYGBgCiMjIERhdGEgVW5kZXJzdGFuZGluZyAKCiMjIyBNaXNzaW5nIHZhbHVlcwpgYGB7cn0KIyBnbG9iYWxfbW9iaWxpdHlfcmVwb3J0ICU+JSBmaWx0ZXIoaXMubmEoc3ViX3JlZ2lvbl8xKSkgJT4lIHNlbGVjdChjb3VudHJ5X3JlZ2lvbikgJT4lCiMgICB1bmlxdWUoKQoKIyBnbG9iYWxfbW9iaWxpdHlfcmVwb3J0ICU+JSBmaWx0ZXIoaXMubmEoc3ViX3JlZ2lvbl8xKSkgJT4lIHNlbGVjdChjb3VudHJ5X3JlZ2lvbikgJT4lCiMgICB1bmlxdWUoKQojIGdsb2JhbF9tb2JpbGl0eV9yZXBvcnQKCiMgZ2xvYmFsX21vYmlsaXR5X3JlcG9ydCAlPiUgZmlsdGVyKGlzLm5hKHN1Yl9yZWdpb25fMSkpICU+JSBmaWx0ZXIoY291bnRyeV9yZWdpb24gPT0gIkdoYW5hIikgJT4lCiMgICBzZWxlY3QoY291bnRyeV9yZWdpb25fY29kZSwgZGF0ZSkgJT4lIGFycmFuZ2UoZGF0ZSkKCiMgZ2xvYmFsX21vYmlsaXR5X3JlcG9ydCAlPiUgZmlsdGVyKGlzLm5hKHN1Yl9yZWdpb25fMSkpICU+JQojICAgIyBmaWx0ZXIoY291bnRyeV9yZWdpb25fY29kZSA9PSAiVVMiKSAlPiUgc2VsZWN0KGRhdGUpICU+JQojIGdyb3VwX2J5KGNvdW50cnlfcmVnaW9uLCBkYXRlKSAlPiUgc2VsZWN0KGRhdGUsIGNvdW50cnlfcmVnaW9uKSAlPiUKIyBmaWx0ZXIobigpPjEpICU+JSBzdW1tYXJpemUobj1uKCkpICU+JSBmaWx0ZXIoY291bnRyeV9yZWdpb24gPT0gIkdoYW5hIikKYmFkX2NvbHMgPC0gYygic3ViX3JlZ2lvbl8yIiwgIm1ldHJvX2FyZWEiLCAiaXNvXzMxNjZfMl9jb2RlIiwgImNlbnN1c19maXBzX2NvZGUiKQpnbG9iYWxfbW9iaWxpdHlfcmVwb3J0IDwtIGdsb2JhbF9tb2JpbGl0eV9yZXBvcnQgJT4lIAogIGZpbHRlcighaXMubmEoc3ViX3JlZ2lvbl8xKSkgJT4lIAogIGdyb3VwX2J5KGNvdW50cnlfcmVnaW9uLCBkYXRlKSAlPiUKICBhcnJhbmdlKGNvdW50cnlfcmVnaW9uLCBzdWJfcmVnaW9uXzEsIGRhdGUpICU+JSAKICBzZWxlY3QoLW9uZV9vZihiYWRfY29scykpCiAgIyBzZWxlY3QoY291bnRyeV9yZWdpb25fY29kZSwgc3ViX3JlZ2lvbl8xLCBkYXRlKSAlPiUKICAjIHVuaXF1ZSgpCmBgYAoKYGBge3J9Cmdsb2JhbF9tb2JpbGl0eV9yZXBvcnQKYGBgCgoKYGBge3J9CiMgZ2xvYmFsX21vYmlsaXR5X3JlcG9ydAp2aXNfbWlzcyhnbG9iYWxfbW9iaWxpdHlfcmVwb3J0LCBzb3J0X21pc3MgPSBULCB3YXJuX2xhcmdlX2RhdGE9IEYpCmBgYAoKCmBgYHtyfQp2aXNfbWlzcyh0eF9kYXRhLCBzb3J0X21pc3MgPSBULCB3YXJuX2xhcmdlX2RhdGE9IEYpCnZpc19taXNzKHN1YnNldF9jZW5zdXMsIHNvcnRfbWlzcyA9IFQsIHdhcm5fbGFyZ2VfZGF0YSA9IEYpCmBgYAojIyMgRHVwbGljYXRlIERhdGEKCmBgYHtyfQpnZXRfZHVwZXMobG9hZF9maWxlKCIuLy4uL2RhdGEvR2xvYmFsX01vYmlsaXR5X1JlcG9ydC5jc3YiKSkKYGBgCgpgYGB7cn0KIyBnbG9iYWxfbW9iaWxpdHlfcmVwb3J0W2R1cGxpY2F0ZWQoZ2xvYmFsX21vYmlsaXR5X3JlcG9ydCldCm1vYmlsaXR5X2R1cGVzIDwtIGdldF9kdXBlcyhnbG9iYWxfbW9iaWxpdHlfcmVwb3J0KQpjZW5zdXNfZHVwZXMgPC0gZ2V0X2R1cGVzKHN1YnNldF9jZW5zdXMpCnR4X2R1cGVzIDwtIGdldF9kdXBlcyh0eF9kYXRhKQoKbW9iaWxpdHlfZHVwZXMKY2Vuc3VzX2R1cGVzCnR4X2R1cGVzCmBgYApgYGB7cn0KbW9iaWxpdHlfZHVwZXMgJT4lIHVuZ3JvdXAoKQpgYGAKYGBge3J9Cm1vYmlsaXR5X2R1cGVzICU+JSB1bmdyb3VwKCkgJT4lIGZpbHRlcihjb3VudHJ5X3JlZ2lvbiA9PSAiVW5pdGVkIFN0YXRlcyIpCmBgYAoKCiMgR3JhcGhzCmBgYHtyfQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKcGxvdF92c19jb3VudHkgPC0gZnVuY3Rpb24oZGYsIGNvbF92YWwsIHBlcmNlbnRpbGU9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpcHNfdGl0bGU9ImNvdW50eV9maXBzX2NvZGUiLCBiYW5rcz02LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kX3RpdGxlPSIiLCBncmFwaGljX3RpdGxlPSIiKXsKICAjIFN1YnNldCBmb3Igc3BlZWQgCiAgZGYgPC0gZGZbYyhmaXBzX3RpdGxlLCBjb2xfdmFsKV0KICAKICAjIEdldCBjb3VudHkgZGF0YQogIGdjb3VudHkgPC0gZ2dwbG90Mjo6bWFwX2RhdGEoImNvdW50eSIpCiAgIyBVU0EgbWFwIGRhdGEKICBndXNhIDwtIG1hcF9kYXRhKCJzdGF0ZSIpCiAgCiAgaWYgKGJhbmtzID4gOSl7CiAgICBteWNvbG9ycyA8LSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOSwgIlJlZHMiKSkoYmFua3MpCiAgfQogIAogICMgRm9ybWF0IHdpdGggc3VicmVnaW9ucwogIGZpcHN0YWIgPC0KICAgICAgdHJhbnNtdXRlKG1hcHM6OmNvdW50eS5maXBzLCBmaXBzLCBjb3VudHkgPSBzdWIoIjouKiIsICIiLCBwb2x5bmFtZSkpICU+JQogICAgICB1bmlxdWUoKSAlPiUKICAgICAgc2VwYXJhdGUoY291bnR5LCBjKCJyZWdpb24iLCAic3VicmVnaW9uIiksIHNlcCA9ICIsIikKICAKICAjIENvbWJpbmUgaW4gZGVzaXJlZCBvcmRlciAoTkEgZm9yIG1pc3NpbmcpCiAgZ2NvdW50eSA8LSBsZWZ0X2pvaW4oZ2NvdW50eSwgZmlwc3RhYiwgYygicmVnaW9uIiwgInN1YnJlZ2lvbiIpKQoKCiAgZGlzIDwtIGRmCiAgZGlzJHJwcm9wIDwtIHJhbmsoZGZbY29sX3ZhbF0pCiAgZGlzJHBjbHMgPC0gY3V0KDEwMCAqIHBlcmNlbnRfcmFuayhkZltjb2xfdmFsXSksIHNlcSgwLCAxMDAsIGxlbiA9IGJhbmtzKSwKICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKQoKICAjIE1pc3NpbmcgZGF0YQogIGFudGlfam9pbihnY291bnR5LCBkaXMsIGJ5ID0gYygiZmlwcyIgPSBmaXBzX3RpdGxlKSkgJT4lCiAgICBzZWxlY3QocmVnaW9uLCBzdWJyZWdpb24pICU+JQogICAgdW5pcXVlKCkKICBnY291bnR5X3BvcCA8LSBsZWZ0X2pvaW4oZ2NvdW50eSwgZGlzLCBieSA9IGMoImZpcHMiID0gZmlwc190aXRsZSkpCiAgZmlsbF92YWxzIDwtIGdjb3VudHlfcG9wW2NvbF92YWxdCgogICMgUGxvdAogIGlmIChsZWdlbmRfdGl0bGUgPT0gIiIpewogICAgbGVnZW5kX3RpdGxlIDwtIGNvbF92YWwKICB9CgogIGlmIChwZXJjZW50aWxlID09IEZBTFNFKXsKICAgICMgbmFtZXMoZ2NvdW50eV9wb3ApW25hbWVzKGdjb3VudHlfcG9wKSA9PSBjb2xfdmFsXSA8LSAiY29sX29mX2ludGVyZXN0IgogICAgcGx0IDwtIGdncGxvdChnY291bnR5X3BvcCkgKwogICAgICBnZW9tX3BvbHlnb24oYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IGdldChjb2xfdmFsKSksCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJncmV5Iiwgc2l6ZSA9IDAuMSwgbmFtZT0iUGVyY2VudCBJbmZlY3RlZCIpICsKICAgICAgZ2VvbV9wb2x5Z29uKGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXApLAogICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLCBkYXRhID0gZ3VzYSwgY29sb3IgPSAibGlnaHRncmV5IikgKwogICAgICBjb29yZF9tYXAoImJvbm5lIiwgcGFyYW1ldGVycyA9IDQxLjYpICsgZ2d0aGVtZXM6OnRoZW1lX21hcCgpKwogICAgICBzY2FsZV9maWxsX2dyYWRpZW50MigpCiAgICAgICAjIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJyZWQiLCBuYS52YWx1ZSA9ICJncmV5IikKICAgICAgIyBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvdXJzID0gdGVycmFpbi5jb2xvcnMoMTApKQogIH0KCiAgaWYgKHBlcmNlbnRpbGUgPT0gVFJVRSl7CiAgICBwbHQgPC0gZ2dwbG90KGdjb3VudHlfcG9wKSArCiAgICAgIGdlb21fcG9seWdvbihhZXMobG9uZywgbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsID0gcGNscyksCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJncmV5Iiwgc2l6ZSA9IDAuMSkgKwogICAgICBnZW9tX3BvbHlnb24oYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBncm91cCksCiAgICAgICAgICAgICAgICAgICBmaWxsID0gTkEsIGRhdGEgPSBndXNhLCBjb2xvciA9ICJsaWdodGdyZXkiKSArCiAgICAgIGNvb3JkX21hcCgiYm9ubmUiLCBwYXJhbWV0ZXJzID0gNDEuNikgKyBnZ3RoZW1lczo6dGhlbWVfbWFwKCkgKwogICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBteWNvbG9ycywgbmEudmFsdWUgPSAiZ3JleSIpICsKICAgICAgIyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gInZpcmlkaXMiLCBuYS52YWx1ZSA9ICJncmV5IikgKwogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWx2ZXRpY2EiLCBmYWNlID0gImJvbGQiLCBzaXplID0gKDE1KSksCiAgICAgICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksIAogICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibGVmdCIpCiAgfQogIHBsdCA8LSBwbHQgKyBsYWJzKGZpbGw9bGVnZW5kX3RpdGxlKSArIGdndGl0bGUoZ3JhcGhpY190aXRsZSkKICBwbHQKfQpgYGAKCmBgYHtyfQpzdWJzZXRfY2Vuc3VzCmBgYAoKYGBge3J9CnN1YnNldF9jZW5zdXNbJ3BjdF9pbmZlY3RlZCddIDwtIHN1YnNldF9jZW5zdXNbJ2NvbmZpcm1lZF9jYXNlcyddL3N1YnNldF9jZW5zdXNbJ3RvdGFsX3BvcCddCnN1YnNldF9jZW5zdXNbJ3BjdF9kZWF0aHMnXSA8LSBzdWJzZXRfY2Vuc3VzWydkZWF0aHMnXS9zdWJzZXRfY2Vuc3VzWyd0b3RhbF9wb3AnXQpzdWJzZXRfY2Vuc3VzJGRlYXRoX3JhdGUgPC0gc3Vic2V0X2NlbnN1cyRkZWF0aHMvc3Vic2V0X2NlbnN1cyRjb25maXJtZWRfY2FzZXMKc3Vic2V0X2NlbnN1cyRjb3VudHlfZmlwc19jb2RlIDwtYXMuaW50ZWdlcihzdWJzZXRfY2Vuc3VzJGNvdW50eV9maXBzX2NvZGUpCnN1YnNldF9jZW5zdXMkZWxkZXJseV9wb3AgPC0gc3Vic2V0X2NlbnN1cyRtYWxlX2VsZGVybHlfcG9wICsgc3Vic2V0X2NlbnN1cyRmZW1hbGVfZWxkZXJseV9wb3AKc3Vic2V0X2NlbnN1cyRwY3RfZWxkZXJseSA8LSBzdWJzZXRfY2Vuc3VzJGVsZGVybHlfcG9wL3N1YnNldF9jZW5zdXMkdG90YWxfcG9wCnN1YnNldF9jZW5zdXMKYGBgCmBgYHtyfQpwbG90X3ZzX2NvdW50eShzdWJzZXRfY2Vuc3VzLCAicGN0X2luZmVjdGVkIiwgbGVnZW5kX3RpdGxlID0gIlBlcmNlbnQgSW5mZWN0ZWQiKQpwbG90X3ZzX2NvdW50eShzdWJzZXRfY2Vuc3VzLCAicGN0X2luZmVjdGVkIiwgcGVyY2VudGlsZSA9IFRSVUUsIGJhbmtzPTExLCAKICAgICAgICAgICAgICAgbGVnZW5kX3RpdGxlID0gIlBlcmNlbnRpbGUgSW5mZWN0ZWQiLAogICAgICAgICAgICAgICBncmFwaGljX3RpdGxlID0gIlBlcmNlbnRpbGUgb2YgUGVyY2VudGFnZSBvZiBQZW9wbGUgSW5mZWN0ZWQgYnkgQ291bnR5IikKcGxvdF92c19jb3VudHkoc3Vic2V0X2NlbnN1cywgInBjdF9kZWF0aHMiLCBwZXJjZW50aWxlID0gVFJVRSwgYmFua3M9MTEsIAogICAgICAgICAgICAgICBsZWdlbmRfdGl0bGUgPSAiUGVyY2VudGlsZSBEZWF0aHMiLAogICAgICAgICAgICAgICBncmFwaGljX3RpdGxlID0gIlBlcmNlbnRpbGUgb2YgUGVyY2VudGFnZSBvZiBEZWF0aHMgYnkgQ291bnR5IikKcGxvdF92c19jb3VudHkoc3Vic2V0X2NlbnN1cywgImRlYXRoX3JhdGUiLCBwZXJjZW50aWxlID0gVFJVRSwgYmFua3M9MTEsIAogICAgICAgICAgICAgICBsZWdlbmRfdGl0bGUgPSAiUGVyY2VudGlsZSBNb3J0YWxpdHkgUmF0ZSIsCiAgICAgICAgICAgICAgIGdyYXBoaWNfdGl0bGUgPSAiUGVyY2VudGlsZSBvZiBNb3J0YWxpdHkgUmF0ZSBieSBDb3VudHkiKQpwbG90X3ZzX2NvdW50eShzdWJzZXRfY2Vuc3VzLCAiZGVhdGhfcmF0ZSIsIAogICAgICAgICAgICAgICBsZWdlbmRfdGl0bGUgPSAiUGVyY2VudGlsZSBNb3J0YWxpdHkgUmF0ZSIsCiAgICAgICAgICAgICAgIGdyYXBoaWNfdGl0bGUgPSAiUGVyY2VudGlsZSBvZiBNb3J0YWxpdHkgUmF0ZSBieSBDb3VudHkiKQpgYGAKYGBge3J9Cm5vcm1lZF9jZW5zdXNfYXR0cmlidXRlcwpgYGAKCgpgYGB7cn0KcGxvdF92c19jb3VudHkoc3Vic2V0X2NlbnN1cywgInRvdGFsX3BvcCIsIAogICAgICAgICAgICAgICBwZXJjZW50aWxlID0gVCwKICAgICAgICAgICAgICAgYmFua3MgPSAxMSwKICAgICAgICAgICAgICAgbGVnZW5kX3RpdGxlID0gIlBlcmNlbnRpbGUiLAogICAgICAgICAgICAgICBncmFwaGljX3RpdGxlID0gIlBvcHVsYXRpb24gRGVuc2l0eSBieSBDb3VudHkiKQpwbG90X3ZzX2NvdW50eShzdWJzZXRfY2Vuc3VzLCAibWVkaWFuX2luY29tZSIsIAogICAgICAgICAgICAgICBwZXJjZW50aWxlID0gVCwKICAgICAgICAgICAgICAgYmFua3MgPSAxMSwKICAgICAgICAgICAgICAgbGVnZW5kX3RpdGxlID0gIlBlcmNlbnRpbGUgb2YgTWVkaWFuIEluY29tZSIsCiAgICAgICAgICAgICAgIGdyYXBoaWNfdGl0bGUgPSAiTWVkaWFuIEluY29tZSBieSBDb3VudHkiKQpwbG90X3ZzX2NvdW50eShub3JtZWRfY2Vuc3VzX2F0dHJpYnV0ZXMgJT4lIAogICAgICAgICAgICAgICAgIG11dGF0ZShjb3VudHlfZmlwc19jb2RlID0gc3Vic2V0X2NlbnN1cyRjb3VudHlfZmlwc19jb2RlKSwKICAgICAgICAgICAgICAgInBjdF9lbGRlcmx5IiwgCiAgICAgICAgICAgICAgIHBlcmNlbnRpbGUgPSBULAogICAgICAgICAgICAgICBiYW5rcyA9IDExLAogICAgICAgICAgICAgICBsZWdlbmRfdGl0bGUgPSAiUGVyY2VudGlsZSBvZiBFbGRlcmx5IFBvcHVsYXRpb24iLAogICAgICAgICAgICAgICBncmFwaGljX3RpdGxlID0gIkVsZGVybHkgUG9wdWxhdGlvbiBieSBDb3VudHkiKQpgYGAKCgpgYGB7cn0KY2Vuc3VzX2NvcnJfY29scyA8LSBjb2xuYW1lcyhzdWJzZXRfY2Vuc3VzKQpjZW5zdXNfY29ycl9jb2xzIDwtIGNlbnN1c19jb3JyX2NvbHNbLTFdCmNlbnN1c19jb3JyX2NvbHMKYGBgCgpgYGB7cn0Kc3Vic2V0X2NlbnN1cwpgYGAKYGBge3J9CmtlZXBfY29scyA8LSBjKCJjb25maXJtZWRfY2FzZXMiLCAiZGVhdGhzIiwgIm1lZGlhbl9pbmNvbWUiLCAibWFsZV9wb3AiLCAiZmVtYWxlX3BvcCIsICJ0b3RhbF9wb3AiLCAibWVkaWFuX2FnZSIsICJ3b3JrZWRfYXRfaG9tZSIsICJtYWxlXzY1X3RvXzY2IiwgIm1hbGVfNjdfdG9fNjkiLCAKICAgICAgICAgICAgICAgIm1hbGVfNzBfdG9fNzQiLCAibWFsZV83NV90b183OSIsICJtYWxlXzgwX3RvXzg0IiwKICAgICAgICAgICAgICAgIm1hbGVfODVfYW5kX292ZXIiLCAiZmVtYWxlXzY1X3RvXzY2IiwgImZlbWFsZV82N190b182OSIsIAogICAgICAgICAgICAgICAiZmVtYWxlXzcwX3RvXzc0IiwgImZlbWFsZV83NV90b183OSIsICJmZW1hbGVfODBfdG9fODQiLAogICAgICAgICAgICAgICAiZmVtYWxlXzg1X2FuZF9vdmVyIikKZ2djb3JyKGNhc2VzX3BsdXNfY2Vuc3VzW2tlZXBfY29sc10sIAogICAgICAgbG93PSJyZWQiLCBtaWQ9ImdyZXkiLCBoaWdoPSJibHVlIiwgaGp1c3Q9IDEsIHNpemU9MywgCiAgICAgICBsYWJlbCA9IFRSVUUsIGxhYmVsX3NpemUgPSAzLCBsYWJlbF9jb2xvciA9ICJ3aGl0ZSIsIGxheW91dC5leHAgPSA0KSArCiAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9ICJQZWFyc29uIENvcnJlbGF0aW9uIG9mIEltcG9ydGFudCBWYXJpYWJsZXMgaW4gdGhlIFUuUy4gQ2Vuc3VzIikKCmdnc2F2ZSgiLi8uLi9pbWdzL3NtYWxsX2NlbnN1c19wZWFyc29uLnBuZyIpCmBgYApgYGB7cn0KIyBrZWVwX2NvbHMgPC0gYygiY291bnR5X2ZpcHNfY29kZSIsICJjb25maXJtZWRfY2FzZXMiLCAiZGVhdGhzIiwgIm1lZGlhbl9pbmNvbWUiLCAibWFsZV9wb3AiLCAiZmVtYWxlX3BvcCIsICJ0b3RhbF9wb3AiLCAibWVkaWFuX2FnZSIsICJ3b3JrZWRfYXRfaG9tZSIsICJtYWxlXzY1X3RvXzY2IiwgIm1hbGVfNjdfdG9fNjkiLCAKIyAgICAgICAgICAgICAgICAibWFsZV83MF90b183NCIsICJtYWxlXzc1X3RvXzc5IiwgIm1hbGVfODBfdG9fODQiLAojICAgICAgICAgICAgICAgICJtYWxlXzg1X2FuZF9vdmVyIiwgImZlbWFsZV82NV90b182NiIsICJmZW1hbGVfNjdfdG9fNjkiLCAKIyAgICAgICAgICAgICAgICAiZmVtYWxlXzcwX3RvXzc0IiwgImZlbWFsZV83NV90b183OSIsICJmZW1hbGVfODBfdG9fODQiLAojICAgICAgICAgICAgICAgICJmZW1hbGVfODVfYW5kX292ZXIiKQprZWVwX2NvbHMgPC0gYygiY291bnR5X2ZpcHNfY29kZSIsICJjb25maXJtZWRfY2FzZXMiLCAiZGVhdGhzIiwgIm1lZGlhbl9pbmNvbWUiLCAibWFsZV9wb3AiLCAiZmVtYWxlX3BvcCIsICJ0b3RhbF9wb3AiLCAibWVkaWFuX2FnZSIsICJ3b3JrZWRfYXRfaG9tZSIsICJtYWxlXzY1X3RvXzY2IiwgIm1hbGVfNjdfdG9fNjkiLCAKICAgICAgICAgICAgICAgIm1hbGVfNzBfdG9fNzQiLCAibWFsZV83NV90b183OSIsICJtYWxlXzgwX3RvXzg0IiwKICAgICAgICAgICAgICAgIm1hbGVfODVfYW5kX292ZXIiLCAiZmVtYWxlXzY1X3RvXzY2IiwgImZlbWFsZV82N190b182OSIsIAogICAgICAgICAgICAgICAiZmVtYWxlXzcwX3RvXzc0IiwgImZlbWFsZV83NV90b183OSIsICJmZW1hbGVfODBfdG9fODQiLAogICAgICAgICAgICAgICAiZmVtYWxlXzg1X2FuZF9vdmVyIikKCmdyb3VwX2tlZXBzIDwtIGxpc3QoYygiY291bnR5X2ZpcHNfY29kZSIsICJjb25maXJtZWRfY2FzZXMiKSwgCiAgICAgICAgICAgICAgICAgICAgYygiY291bnR5X2ZpcHNfY29kZSIsICJkZWF0aHMiKSwKICAgICAgICAgICAgICAgICAgICBjKCJjb3VudHlfZmlwc19jb2RlIiwgIm1lZGlhbl9pbmNvbWUiKSwKICAgICAgICAgICAgICAgICAgICBjKCJjb3VudHlfZmlwc19jb2RlIiwgIm1hbGVfcG9wIiwgImZlbWFsZV9wb3AiLCAidG90YWxfcG9wIiksCiAgICAgICAgICAgICAgICAgICAgYygiY291bnR5X2ZpcHNfY29kZSIsICJtZWRpYW5fYWdlIiksIAogICAgICAgICAgICAgICAgICAgIGMoImNvdW50eV9maXBzX2NvZGUiLCAibWFsZV82NV90b182NiIsICJtYWxlXzY3X3RvXzY5IiwgCiAgICAgICAgICAgICAgICJtYWxlXzcwX3RvXzc0IiwgIm1hbGVfNzVfdG9fNzkiLCAibWFsZV84MF90b184NCIsCiAgICAgICAgICAgICAgICJtYWxlXzg1X2FuZF9vdmVyIiwgImZlbWFsZV82NV90b182NiIsICJmZW1hbGVfNjdfdG9fNjkiLCAKICAgICAgICAgICAgICAgImZlbWFsZV83MF90b183NCIsICJmZW1hbGVfNzVfdG9fNzkiLCAiZmVtYWxlXzgwX3RvXzg0IiwKICAgICAgICAgICAgICAgImZlbWFsZV84NV9hbmRfb3ZlciIpKQoKIyBmb3IgKGtlZXBfY29sIGluIGdyb3VwX2tlZXBzKSB7CiMgICBwbHQgPC0gY2FzZXNfcGx1c19jZW5zdXNba2VlcF9jb2xdICU+JSAKIyAgICAgcGl2b3RfbG9uZ2VyKCFjb3VudHlfZmlwc19jb2RlLCBuYW1lc190byA9ICJWYXJpYWJsZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQojICAgICBzZWxlY3QoVmFyaWFibGUsIHZhbHVlKSAlPiUKIyAgICAgZ2dwbG90KGFlcyh4PVZhcmlhYmxlLCB5PXZhbHVlLCBmaWxsPVZhcmlhYmxlKSkgKwojICAgICAgIGdlb21fYm94cGxvdCgpICsKIyAgICAgICAjIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUsIGFscGhhPTAuNiwgb3B0aW9uPSJBIikgKwojICAgICAgICMgdGhlbWVfaXBzdW0oKSArCiMgICAgICAgIyB0aGVtZSgKIyAgICAgICAjICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIiwKIyAgICAgICAjICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTExKQojICAgICAgICMgKSArCiMgICAgICAgZ2d0aXRsZSgiVmlvbGluIGNoYXJ0IikgKwojICAgICAgIGdlb21faml0dGVyKHNpemU9LjUpKwojICAgICAgIHhsYWIoIiIpCiMgICBwcmludChwbHQpCiMgICAKIyB9CgojIG9uZXNfdG9fbG9va19hdCA8LSBjKCJjb3VudHlfZmlwc19jb2RlIiwgIm1hbGVfNjVfdG9fNjYiLCAibWFsZV82N190b182OSIsIAojICAgICAgICAgICAgICAgICJtYWxlXzcwX3RvXzc0IiwgIm1hbGVfNzVfdG9fNzkiLCAibWFsZV84MF90b184NCIsCiMgICAgICAgICAgICAgICAgIm1hbGVfODVfYW5kX292ZXIiLCAiZmVtYWxlXzY1X3RvXzY2IiwgImZlbWFsZV82N190b182OSIsIAojICAgICAgICAgICAgICAgICJmZW1hbGVfNzBfdG9fNzQiLCAiZmVtYWxlXzc1X3RvXzc5IiwgImZlbWFsZV84MF90b184NCIsCiMgICAgICAgICAgICAgICAgImZlbWFsZV84NV9hbmRfb3ZlciIpCiMgcGx0IDwtIGNhc2VzX3BsdXNfY2Vuc3VzW29uZXNfdG9fbG9va19hdF0gJT4lIAojICAgICBwaXZvdF9sb25nZXIoIWNvdW50eV9maXBzX2NvZGUsIG5hbWVzX3RvID0gIlZhcmlhYmxlIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lCiMgICAgIHNlbGVjdChWYXJpYWJsZSwgdmFsdWUpICU+JQojICAgICBnZ3Bsb3QoYWVzKHg9VmFyaWFibGUsIHk9dmFsdWUsIGZpbGw9VmFyaWFibGUsIGxheW91dC5leHAgPTIwICkpICsKIyAgICAgICBnZW9tX2JveHBsb3QobGF5b3V0LmV4cCA9IDIwKSArCiMgICAgICAgIyBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFLCBhbHBoYT0wLjYsIG9wdGlvbj0iQSIpICsKIyAgICAgICAjIHRoZW1lX2lwc3VtKCkgKwojICAgICAgICMgdGhlbWUoCiMgICAgICAgIyAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsCiMgICAgICAgIyAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMSkKIyAgICAgICAjICkgKwojICAgICAgIGdndGl0bGUoIlZpb2xpbiBjaGFydCIpICsKIyAgICAgICAjIGdlb21faml0dGVyKHNpemU9LjUpKwojICAgICAgIHhsYWIoIiIpCiMgICBwcmludChwbHQpCgprZWVwX2NvbHMgPC0gYygiY291bnR5X2ZpcHNfY29kZSIsICJjb25maXJtZWRfY2FzZXMiLCAiZGVhdGhzIiwgIm1lZGlhbl9pbmNvbWUiLCAibWVkaWFuX2FnZSIsICJ3b3JrZWRfYXRfaG9tZSIpCgpwbHQgPC0gY2FzZXNfcGx1c19jZW5zdXNba2VlcF9jb2xzXSAlPiUgCiAgICBwaXZvdF9sb25nZXIoIWNvdW50eV9maXBzX2NvZGUsIG5hbWVzX3RvID0gIlZhcmlhYmxlIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lCiAgICBzZWxlY3QoVmFyaWFibGUsIHZhbHVlKSAlPiUKICBnZ3Bsb3QoCiAgICBhZXMoeD1WYXJpYWJsZSwgeT12YWx1ZSwgZmlsbD1WYXJpYWJsZSkpKwogIGdlb21fYm94cGxvdCgpKwogICMgICBhZXMoeD12YWx1ZSwgY29sb3I9VmFyaWFibGUsIGZpbGw9VmFyaWFibGUpKSsKICAjIGdlb21faGlzdG9ncmFtKCkrCiAgCiAgICAjIGFlcyh4PVZhcmlhYmxlLCB5PXZhbHVlLCBmaWxsPVZhcmlhYmxlKSkrCiAgIyBnZW9tX3Zpb2xpbigpKwoKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTYpKSsKICAjIHhsYWIoIlBvcHVsYXRpb24iKSArCiAgIyB5bGFiKCJBc3NpZ25lZCBQcm9iYWJpbGl0eSAoJSkiKSArCiAgZmFjZXRfd3JhcCh+VmFyaWFibGUpCnBsdApgYGAKCgoKCgoKYGBge3J9CiMgb25lc190b19sb29rX2F0IDwtIGMoImNvdW50eV9maXBzX2NvZGUiLCAibWFsZV82NV90b182NiIsICJtYWxlXzY3X3RvXzY5IiwKIyAgICAgICAgICAgICAgICAibWFsZV83MF90b183NCIsICJtYWxlXzc1X3RvXzc5IiwgIm1hbGVfODBfdG9fODQiLAojICAgICAgICAgICAgICAgICJtYWxlXzg1X2FuZF9vdmVyIiwgImZlbWFsZV82NV90b182NiIsICJmZW1hbGVfNjdfdG9fNjkiLAojICAgICAgICAgICAgICAgICJmZW1hbGVfNzBfdG9fNzQiLCAiZmVtYWxlXzc1X3RvXzc5IiwgImZlbWFsZV84MF90b184NCIsCiMgICAgICAgICAgICAgICAgImZlbWFsZV84NV9hbmRfb3ZlciIpCiMgb25lc190b19sb29rX2F0IDwtIGMoImNvdW50eV9maXBzX2NvZGUiLCAibWFsZV82NV90b182NiIsICJtYWxlXzY3X3RvXzY5IikKcGx0IDwtIGNhc2VzX3BsdXNfY2Vuc3VzW29uZXNfdG9fbG9va19hdF0gJT4lIAogIHBpdm90X2xvbmdlcighY291bnR5X2ZpcHNfY29kZSwgbmFtZXNfdG8gPSAiVmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBzZWxlY3QoVmFyaWFibGUsIHZhbHVlKSAlPiUKIyAgIGdhdGhlcihWYXJpYWJsZSwgdmFsdWUsIC1jb3VudHlfZmlwc19jb2RlKSAlPiUKIyAgICAgZ2dwbG90KGFlcyh2YWx1ZSwgZmlsbCA9IFZhcmlhYmxlKSkgKyBnZW9tX2hpc3RvZ3JhbSgpICsgZmFjZXRfd3JhcCh+Y291bnR5X2ZpcHNfY29kZSkKIyAKIyBwbHQKCiAgZ2dwbG90KCBhZXMoeD12YWx1ZSwgY29sb3I9VmFyaWFibGUsIGZpbGw9VmFyaWFibGUpKSArCiAgICAgIGdlb21faGlzdG9ncmFtKGFscGhhPTAuNiwgYmlud2lkdGggPSA1KSArCiAgICAgICMgc2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlPVRSVUUpICsKICAgICAgIyBzY2FsZV9jb2xvcl92aXJpZGlzKGRpc2NyZXRlPVRSVUUpICsKICAgICAgIyB0aGVtZV9pcHN1bSgpICsKICAgICAgIyB0aGVtZSgKICAgICAgIyAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsCiAgICAgICMgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjEsICJsaW5lcyIpLAogICAgICAjICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KQogICAgICAjICkgKwogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTYpKSsKICAgICAgeGxhYigiUG9wdWxhdGlvbiIpICsKICAgICAgeWxhYigiQXNzaWduZWQgUHJvYmFiaWxpdHkgKCUpIikgKwogICAgICBmYWNldF93cmFwKH5WYXJpYWJsZSkKCnBsdApgYGAKCmBgYHtyfQojIHBuZygiLi90ZXN0LnBuZyIsIHdpZHRoPTgwMCwgaGVpZ2h0ID0gODAwKQpjZW5zdXNfY29ycl9jb2xzIDwtIGNvbG5hbWVzKHN1YnNldF9jZW5zdXMpCmNlbnN1c19jb3JyX2NvbHMgPC0gY2Vuc3VzX2NvcnJfY29sc1stMV0Kbm9ybWVkX2NlbnN1c19hdHRyaWJ1dGVzIDwtIHN1YnNldF9jZW5zdXNbY2Vuc3VzX2NvcnJfY29sc10gJT4lCiAgbXV0YXRlKHBjdF9mZW1hbGVfZWxkZXJseSA9IGZlbWFsZV9lbGRlcmx5X3BvcC90b3RhbF9wb3AsCiAgICAgICAgIHBjdF9tYWxlX2VsZGVybHkgPSBtYWxlX2VsZGVybHlfcG9wL3RvdGFsX3BvcCwKICAgICAgICAgcGN0X3dvcmtlZF9hdF9ob21lID0gd29ya2VkX2F0X2hvbWUvdG90YWxfcG9wLAogICAgICAgICBwY3RfZmVtYWxlX3BvcCA9IGZlbWFsZV9wb3AvdG90YWxfcG9wLAogICAgICAgICBwY3RfbWFsZV9wb3AgPSBtYWxlX3BvcC90b3RhbF9wb3ApICU+JQogIHJlbmFtZShtb3J0YWxpdHlfcmF0ZSA9IGRlYXRoX3JhdGUpICU+JQogIHNlbGVjdChtb3J0YWxpdHlfcmF0ZSwgcGN0X2RlYXRocywgcGN0X2luZmVjdGVkLCBwY3RfZWxkZXJseSwKICAgICAgICAgcGN0X2ZlbWFsZV9lbGRlcmx5LCBwY3RfbWFsZV9lbGRlcmx5LCBwY3RfZmVtYWxlX3BvcCwgcGN0X21hbGVfcG9wLAogICAgICAgICBwY3Rfd29ya2VkX2F0X2hvbWUsIG1lZGlhbl9hZ2UsIG1lZGlhbl9pbmNvbWUpCiAgCmdnY29ycihub3JtZWRfY2Vuc3VzX2F0dHJpYnV0ZXMsIGxvdz0icmVkIiwgbWlkPSJncmV5IiwgaGlnaD0iYmx1ZSIsIGhqdXN0PSAuOSwgc2l6ZT0zLCAKICAgICAgIGxhYmVsID0gVFJVRSwgbGFiZWxfc2l6ZSA9IDMsIGxhYmVsX2NvbG9yID0gIndoaXRlIiwgbGF5b3V0LmV4cCA9IDMpICsKICBnZ3Bsb3QyOjpsYWJzKHRpdGxlID0gIlBlYXJzb24gQ29ycmVsYXRpb24gb2YgSW1wb3J0YW50IFZhcmlhYmxlcyBpbiB0aGUgVS5TLiBDZW5zdXMiKQoKZ2dzYXZlKCIuLy4uL2ltZ3MvY2Vuc3VzX3BlYXJzb24ucG5nIikKCiMgZGV2Lm9mZigpCmBgYApgYGB7cn0KZ2xvYmFsX21vYmlsaXR5X3JlcG9ydApgYGAKCgpgYGB7cn0KY291bnRyeV9kYXRlX3BjdF9jaGFuZ2UgPC0gZ2xvYmFsX21vYmlsaXR5X3JlcG9ydCAlPiUgc2VsZWN0KGNvdW50cnlfcmVnaW9uX2NvZGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgY29udGFpbnMoImRhdGUiKSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgY29udGFpbnMoInBlcmNlbnQiKSkKY291bnRyeV9kYXRlX3BjdF9jaGFuZ2UKYGBgCmBgYHtyfQpjb2lfZG93bnNhbXBsZWQgPC0gY291bnRyeV9kYXRlX3BjdF9jaGFuZ2UgJT4lIGZpbHRlcihjb3VudHJ5X3JlZ2lvbl9jb2RlICVpbiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiVVMiLCAiQ0EiLCAiTloiLCAiQUUiLCAiQ04iLCAiREUiLCAiSlAiKSkgJT4lIAogIGZpbHRlcih3ZWVrZGF5cyhkYXRlKSA9PSAiU2F0dXJkYXkiKSAlPiUgZ3JvdXBfYnkoY291bnRyeV9yZWdpb25fY29kZSwgZGF0ZSkgJT4lIHN1bW1hcmlzZV9hbGwobWVhbiwgbmEucm0gPSBUKSAlPiUgYXJyYW5nZShjb3VudHJ5X3JlZ2lvbl9jb2RlLCBkYXRlKQpjb2lfZG93bnNhbXBsZWQKYGBgCgoKCmBgYHtyfQppbnRlcmVzdGVkX2NvbHMgPC0gYygicmV0YWlsX2FuZF9yZWNyZWF0aW9uX3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUiLAogICAgICAgICAgICAgICAgICAgICAiZ3JvY2VyeV9hbmRfcGhhcm1hY3lfcGVyY2VudF9jaGFuZ2VfZnJvbV9iYXNlbGluZSIsCiAgICAgICAgICAgICAgICAgICAgICJwYXJrc19wZXJjZW50X2NoYW5nZV9mcm9tX2Jhc2VsaW5lIiwKICAgICAgICAgICAgICAgICAgICAgInRyYW5zaXRfc3RhdGlvbnNfcGVyY2VudF9jaGFuZ2VfZnJvbV9iYXNlbGluZSIsCiAgICAgICAgICAgICAgICAgICAgICJ3b3JrcGxhY2VzX3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUiLAogICAgICAgICAgICAgICAgICAgICAicmVzaWRlbnRpYWxfcGVyY2VudF9jaGFuZ2VfZnJvbV9iYXNlbGluZSIpCgpjb2xfbGFiZWxzIDwtIGMoIkF2ZXJhZ2UgUmV0YWlsIGFuZCBSZWNyZWF0aW9uIFBlcmNlbnQgQ2hhbmdlIGZyb20gQmFzZWxpbmUiLAogICAgICAgICAgICAgICAgICAgICAiQXZlcmFnZSBHcm9jZXJ5IGFuZCBQaGFybWFjeSBQZXJjZW50IENoYW5nZSBmcm9tIEJhc2VsaW5lIiwKICAgICAgICAgICAgICAgICAgICAgIkF2ZXJhZ2UgUGFya3MgUGVyY2VudCBDaGFuZ2UgZnJvbSBCYXNlbGluZSIsCiAgICAgICAgICAgICAgICAgICAgICJBdmVyYWdlIFRyYW5zaXQgU3RhdGlvbnMgUGVyY2VudCBDaGFuZ2UgZnJvbSBCYXNlbGluZSIsCiAgICAgICAgICAgICAgICAgICAgICJBdmVyYWdlIFdvcmtwbGFjZXMgUGVyY2VudCBDaGFuZ2UgZnJvbSBCYXNlbGluZSIsCiAgICAgICAgICAgICAgICAgICAgICJBdmVyYWdlIFJlc2lkZW50aWFsIFBlcmNlbnQgQ2hhbmdlIGZyb20gQmFzZWxpbmUiKQoKCmZvciAoaSBpbiAxOmxlbmd0aChjb2xfbGFiZWxzKSl7CiAgcHJpbnQoaSkKICBwbHQgPC0gZ2dwbG90KGNvaV9kb3duc2FtcGxlZCwKICAgICAgIGFlcyh4PWRhdGUsIHk9Z2V0KGludGVyZXN0ZWRfY29sc1tpXSksIGdyb3VwPWNvdW50cnlfcmVnaW9uX2NvZGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1jb3VudHJ5X3JlZ2lvbl9jb2RlKSkrCiAgZ2VvbV9wb2ludChhZXMoeT1yb2xsbWVhbihnZXQoaW50ZXJlc3RlZF9jb2xzW2ldKSwgaz0xMCwgbmEucGFkPVRSVUUpKSwgc2l6ZT0uNSkrCiAgZ2VvbV9saW5lKGFlcyh5PXJvbGxtZWFuKGdldChpbnRlcmVzdGVkX2NvbHNbaV0pLCBrPTEwLCBuYS5wYWQ9VFJVRSkpKSsKICAjIGdlb21fcG9pbnQoc2l6ZT0uNSkrZ2VvbV9saW5lKCkrCiAgbGFicyh5ID0gY29sX2xhYmVsc1tpXSwgeCA9ICJEYXRlIiwgY29sb3IgPSAiQ291bnRyeSIpKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAoMTUpKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKSsKICAgIGdncGxvdDI6OmxhYnModGl0bGUgPSBwYXN0ZSgiU2F0dXJkYXkiLCBjb2xfbGFiZWxzW2ldLCBzZXA9IiAiKSkKICBzYXZlX3BhdGggPC0gcGFzdGUoYygiLi8uLi9pbWdzLyIsIGludGVyZXN0ZWRfY29sc1tpXSwgIi5wbmciKSwgY29sbGFwc2UgPSAiIikKICBnZ3NhdmUoc2F2ZV9wYXRoKQogIHByaW50KHBsdCkKfQojIGdncGxvdChjb2lfZG93bnNhbXBsZWQsCiMgICAgICAgIGFlcyh4PWRhdGUsIHk9Z3JvY2VyeV9hbmRfcGhhcm1hY3lfcGVyY2VudF9jaGFuZ2VfZnJvbV9iYXNlbGluZSwgZ3JvdXA9Y291bnRyeV9yZWdpb25fY29kZSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9Y291bnRyeV9yZWdpb25fY29kZSkpKwogICMgZ2VvbV9wb2ludChhZXMoeT1yb2xsbWVhbihyZXRhaWxfYW5kX3JlY3JlYXRpb25fcGVyY2VudF9jaGFuZ2VfZnJvbV9iYXNlbGluZSwgaz0xMCwgbmEucGFkPVRSVUUpKSwgc2l6ZT0uNSkrCiMgICBnZW9tX2xpbmUoYWVzKHk9cm9sbG1lYW4ocmV0YWlsX2FuZF9yZWNyZWF0aW9uX3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUsIGs9MTAsIG5hLnBhZD1UUlVFKSkpKwojICAgIyBnZW9tX3BvaW50KHNpemU9LjUpK2dlb21fbGluZSgpKwojICAgbGFicyh5ID0gIkF2ZXJhZ2UgR3JvY2VyeSBhbmQgUGhhcm1hY3kgUGVyY2VudCBDaGFuZ2UgZnJvbSBCYXNlbGluZSIsIHggPSAiRGF0ZSIsIGNvbG9yID0gIkNvdW50cnkiKSsKIyAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAoMTUpKSwKIyAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCiMgICAjIGdlb21fbGluZSgpCmBgYAoKYGBge3J9CgpgYGAKCgpgYGB7cn0KdHhfY291bnR5X2RhdGEgPC0gdHhfZGF0YSAlPiUgZmlsdGVyKGNvdW50eV9uYW1lICE9ICJTdGF0ZXdpZGUgVW5hbGxvY2F0ZWQiKQp0eF90b3RhbF9zdGF0ZV9kYXRhIDwtIHR4X2RhdGEgJT4lIGZpbHRlcihjb3VudHlfbmFtZSA9PSAiU3RhdGV3aWRlIFVuYWxsb2NhdGVkIikKdHhfdG90YWxfc3RhdGVfZGF0YSRjdW11bGF0aXZlX2RlYXRocyA8LSBjdW1zdW0odHhfdG90YWxfc3RhdGVfZGF0YSRkZWF0aHMpCnR4X3RvdGFsX3N0YXRlX2RhdGEkY3VtdWxhdGl2ZV9jYXNlcyA8LSBjdW1zdW0odHhfdG90YWxfc3RhdGVfZGF0YSRjb25maXJtZWRfY2FzZXMpCnR4X2NvdW50eV9kYXRhCnR4X3RvdGFsX3N0YXRlX2RhdGEKYGBgCgpgYGB7cn0KY29sX2xhYmVscyA8LSBjKCJBdmVyYWdlIFJldGFpbCBhbmQgUmVjcmVhdGlvbiBQZXJjZW50IENoYW5nZSBmcm9tIEJhc2VsaW5lIiwKICAgICAgICAgICAgICAgICAgICAgIkF2ZXJhZ2UgR3JvY2VyeSBhbmQgUGhhcm1hY3kgUGVyY2VudCBDaGFuZ2UgZnJvbSBCYXNlbGluZSIsCiAgICAgICAgICAgICAgICAgICAgICJBdmVyYWdlIFBhcmtzIFBlcmNlbnQgQ2hhbmdlIGZyb20gQmFzZWxpbmUiLAogICAgICAgICAgICAgICAgICAgICAiQXZlcmFnZSBUcmFuc2l0IFN0YXRpb25zIFBlcmNlbnQgQ2hhbmdlIGZyb20gQmFzZWxpbmUiLAogICAgICAgICAgICAgICAgICAgICAiQXZlcmFnZSBXb3JrcGxhY2VzIFBlcmNlbnQgQ2hhbmdlIGZyb20gQmFzZWxpbmUiLAogICAgICAgICAgICAgICAgICAgICAiQXZlcmFnZSBSZXNpZGVudGlhbCBQZXJjZW50IENoYW5nZSBmcm9tIEJhc2VsaW5lIikKcGFzdGUoIk1vbmRheXMiLCBjb2xfbGFiZWxzWzFdLCBzZXA9IiAiKQpgYGAKCgpTaW5jZSB0aGUgYWJvdmUgZG9lc24ndCByZWFsbHkgbWFrZSBzZW5zZSAob25seSA3OCBjb25maXJtZWQgY2FzZXMgd2l0aCBvdmVyIGEgdGhvdXNhbmQgZGVhdGhzKSwgSSBhbSBnb2luZyB0byBhbmFseXplIG9uIGEgcGVyIGNvdW50eSBiYXNpcyBhbmQgbWF5YmUgdGhhdCBkYXRhIHdpbGwgYmUgbW9yZSBjbGVhci4KCmBgYHtyfQp0eF9ieV9kYXlfYmFzZWRfb25fY291bnR5IDwtIHR4X2NvdW50eV9kYXRhICU+JSAKICBzZWxlY3QoZGF0ZSwgY29uZmlybWVkX2Nhc2VzLCBkZWF0aHMpICU+JQogIGdyb3VwX2J5KGRhdGUpICU+JSAKICBzdW1tYXJpc2VfYWxsKHN1bSwgbmEucm0gPSBUKSAlPiUKICBhcnJhbmdlKGRhdGUpCgojIGludGVyZXN0ZWRfY29scyA8LSBjKCJjb25maXJtZWRfY2FzZXMiLCAiZGVhdGhzIikKIyBjb2xfbGFiZWxzIDwtIGMoIlRvdGFsIENhc2VzIiwgIlRvdGFsIERlYXRocyIpCiMgCiMgZm9yIChpIGluIDE6bGVuZ3RoKGNvbF9sYWJlbHMpKXsKIyAgIHByaW50KGkpCiMgICB0aXRsZSA8LSBwYXN0ZShjKCJUZXhhcyAiLCBjb2xfbGFiZWxzW2ldKSwgY29sbGFwc2UgPSAiIikKIyAgIHBsdCA8LSBnZ3Bsb3QodHhfYnlfZGF5X2Jhc2VkX29uX2NvdW50eSwKIyAgICAgICAgYWVzKHg9ZGF0ZSwgeT1nZXQoaW50ZXJlc3RlZF9jb2xzW2ldKSkpKwojICAgIyBnZW9tX3BvaW50KGFlcyh5PXJvbGxtZWFuKGdldChpbnRlcmVzdGVkX2NvbHNbaV0pLCBrPTEwLCBuYS5wYWQ9VFJVRSkpLCBzaXplPS41KSsKIyAgICMgZ2VvbV9saW5lKGFlcyh5PXJvbGxtZWFuKGdldChpbnRlcmVzdGVkX2NvbHNbaV0pLCBrPTEwLCBuYS5wYWQ9VFJVRSkpKSsKIyAgICMgZ2VvbV9wb2ludChzaXplPS41KStnZW9tX2xpbmUoKSsKIyAgICAgZ2VvbV9saW5lKGNvbG9yKSsKIyAgIGxhYnMoeSA9IGNvbF9sYWJlbHNbaV0sIHggPSAiRGF0ZSIsIHRpdGxlID0gdGl0bGUpCiMgICAjIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAoMTUpKSwKIyAgICMgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkKIyAgICMgc2F2ZV9wYXRoIDwtIHBhc3RlKGMoIi4vLi4vaW1ncy8iLCBpbnRlcmVzdGVkX2NvbHNbaV0sICIucG5nIiksIGNvbGxhcHNlID0gIiIpCiMgICAjIGdnc2F2ZShzYXZlX3BhdGgpCiMgICBwcmludChwbHQpCiMgfQoKYGBgCmBgYHtyfQp0eF9ieV9kYXlfYmFzZWRfb25fY291bnR5CmBgYAoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoImdncmVwZWwiKQpsaWJyYXJ5KGdncmVwZWwpCmBgYApgYGB7cn0KdHhfYnlfZGF5X2Jhc2VkX29uX2NvdW50eSAlPiUgcGl2b3RfbG9uZ2VyKCFkYXRlLCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gImNvdW50IikKYGBgCgoKYGBge3J9CiMgdCA8LSB0aWJibGUoIk1heCIgPSBjKDM0Mzc4LCAyMjQ4OTI3KSwgImRhdGUiID0gYygiMjAyMS0wMS0yNSIsICIyMDIxLTAxLTI1IiksCiMgICAgICAgICAgICAgInR5cGUiID0gYygiZGVhdGhzIiwgImNvbmZpcm1lZF9jYXNlcyIpKQojIHQkZGF0ZSA8LSBhcy5EYXRlKHQkZGF0ZSkKIyB0IAoKZGF0YV9lbmRzIDwtIHR4X2J5X2RheV9iYXNlZF9vbl9jb3VudHkgJT4lIHBpdm90X2xvbmdlcighZGF0ZSwgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJjb3VudCIpICU+JSAKICBncm91cF9ieSh0eXBlKSAlPiUgCiAgdG9wX24oMSwgY291bnQpIApkYXRhX2VuZHMKCmBgYAoKCgpgYGB7cn0KbGlicmFyeShzY2FsZXMpCiMgcG5nKCIuLy4uL2ltZ3MvdGV4YXNfY292aWRfY2FzZXNfdG90YWwucG5nIiwgd2lkdGggPSA4MDAsIGhlaWdodCA9IDgwMCkKIyB0eF9ieV9kYXlfYmFzZWRfb25fY291bnR5ICU+JSBwaXZvdF9sb25nZXIoIWRhdGUsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAiY291bnQiKQpnZ3Bsb3QodHhfYnlfZGF5X2Jhc2VkX29uX2NvdW50eSAlPiUgcGl2b3RfbG9uZ2VyKCFkYXRlLCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gImNvdW50IiksCiAgICAgICBhZXMoeD1kYXRlLCB5PWNvdW50LCBncm91cD10eXBlKSkrCiAgICAgICAgIGdlb21fbGluZShhZXMoY29sb3I9dHlwZSkpKwogICMgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIiwKICAjICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSB0cmFuc19icmVha3MoJ2xvZzEwJywgbWF0aF9mb3JtYXQoMTBeLngpKSkrCiAgc2NhbGVfY29sb3JfbWFudWFsKGxhYmVscyA9IGMoIkNvbmZpcm1lZCBDYXNlcyIsICJEZWF0aHMiKSwgdmFsdWVzID0gYygiY29uZmlybWVkX2Nhc2VzIj0iYmx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZGVhdGhzIj0icmVkIikpKwogIGxhYnMoeSA9ICJUb3RhbCBQZXJzb25zIiwgeCA9ICJEYXRlIiwgY29sb3IgPSAiIikrCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IGNvdW50KSwgZGF0YSA9IGRhdGFfZW5kcywgc2l6ZT0zKSsKICAjIHNjYWxlX3lfY29udGludW91cyhzZWMuYXhpcyA9IHNlY19heGlzKH4gLiwgYnJlYWtzID0gZGF0YV9lbmRzKSkrCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVsdmV0aWNhIiwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9ICgxNSkpKSsKICBnZ3RpdGxlKCJUZXhhcyBDT1ZJRC0xOSBDYXNlcyIpCiAgCiMgcGx0KyAKIyBnZ3Bsb3QodCwgCiMgICAgICAgICAgICAgIGFlcyh4PURhdGUsIHk9IE1heCkpKwojICAgZ2VvbV9wb2ludCgpCiMgcGx0ICsgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IE1heCksIGRhdGEgPSB0LCBmb250ZmFjZT0icGxhaW4iLCBjb2xvcj0iYmxhY2siLAojICAgICAgICAgICAgICAgICAgIHNpemU9MykKIyBkZXYub2ZmKCkKCmdnc2F2ZSgiLi8uLi9pbWdzL3RleGFzX2NvdmlkX2Nhc2VzX3RvdGFsLnBuZyIpCiAgIyBzY2FsZV95X2xvZzEwKCkKICAgICAgICAgIyBsYWJzKHkgPSAiVG90YWwgUGVyc29ucyIsIHggPSAiRGF0ZSIpKQoKIyApCiMgCiMgcGx0IDwtIGdncGxvdChjb2lfZG93bnNhbXBsZWQsCiMgICAgICAgIGFlcyh4PWRhdGUsIHk9Z2V0KGludGVyZXN0ZWRfY29sc1tpXSksIGdyb3VwPWNvdW50cnlfcmVnaW9uX2NvZGUsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPWNvdW50cnlfcmVnaW9uX2NvZGUpKSsKIyAgIGdlb21fcG9pbnQoYWVzKHk9cm9sbG1lYW4oZ2V0KGludGVyZXN0ZWRfY29sc1tpXSksIGs9MTAsIG5hLnBhZD1UUlVFKSksIHNpemU9LjUpKwojICAgZ2VvbV9saW5lKGFlcyh5PXJvbGxtZWFuKGdldChpbnRlcmVzdGVkX2NvbHNbaV0pLCBrPTEwLCBuYS5wYWQ9VFJVRSkpKSsKIyAgICMgZ2VvbV9wb2ludChzaXplPS41KStnZW9tX2xpbmUoKSsKIyAgIGxhYnMoeSA9IGNvbF9sYWJlbHNbaV0sIHggPSAiRGF0ZSIsIGNvbG9yID0gIkNvdW50cnkiKSsKIyAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAoMTUpKSwKIyAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCiMgICBzYXZlX3BhdGggPC0gcGFzdGUoYygiLi8uLi9pbWdzLyIsIGludGVyZXN0ZWRfY29sc1tpXSwgIi5wbmciKSwgY29sbGFwc2UgPSAiIikKIyAgIGdnc2F2ZShzYXZlX3BhdGgpCiMgICBwcmludChwbHQpCmBgYAoKYGBge3J9CnR4X2NvdW50eV9kYXRhCmBgYAoKCmBgYHtyfQpzdWJzZXRfY2Vuc3VzCgp0eF9zdGF0ZSA8LSBtYXBfZGF0YSgic3RhdGUiKSAlPiUgc3Vic2V0KHJlZ2lvbiA9PSAidGV4YXMiKQp0eF9jb3VudHlfbWFwX2RhdGEgPC0gbWFwX2RhdGEoImNvdW50eSIpICU+JSBzdWJzZXQocmVnaW9uID09ICJ0ZXhhcyIpCgp0eF9zdGF0ZQp0eF9jb3VudHlfbWFwX2RhdGEKCmdjb3VudHkgPC0gbWFwX2RhdGEoImNvdW50eSIpCiMgCiMgZmlwc3RhYiA8LQojICAgICAgIHRyYW5zbXV0ZShtYXBzOjpjb3VudHkuZmlwcywgZmlwcywgY291bnR5ID0gc3ViKCI6LioiLCAiIiwgcG9seW5hbWUpKSAlPiUKIyAgICAgICB1bmlxdWUoKSAlPiUKIyAgICAgICBzZXBhcmF0ZShjb3VudHksIGMoInJlZ2lvbiIsICJzdWJyZWdpb24iKSwgc2VwID0gIiwiKQoKIyBGb3JtYXQgd2l0aCBzdWJyZWdpb25zCmZpcHN0YWIgPC0KICB0cmFuc211dGUobWFwczo6Y291bnR5LmZpcHMsIGZpcHMsIGNvdW50eSA9IHN1YigiOi4qIiwgIiIsIHBvbHluYW1lKSkgJT4lCiAgdW5pcXVlKCkgJT4lCiAgc2VwYXJhdGUoY291bnR5LCBjKCJyZWdpb24iLCAic3VicmVnaW9uIiksIHNlcCA9ICIsIikKICAKICAjICMgQ29tYmluZSBpbiBkZXNpcmVkIG9yZGVyIChOQSBmb3IgbWlzc2luZykKICAjIGdjb3VudHkgPC0gbGVmdF9qb2luKGdjb3VudHksIGZpcHN0YWIsIGMoInJlZ2lvbiIsICJzdWJyZWdpb24iKSkKCgp0eF9nZW9fZGF0YSA8LSBsZWZ0X2pvaW4oZ2NvdW50eSwgZmlwc3RhYiwgYygicmVnaW9uIiwgInN1YnJlZ2lvbiIpKSAlPiUKICBsZWZ0X2pvaW4oc3Vic2V0X2NlbnN1cywgYygiZmlwcyIgPSAiY291bnR5X2ZpcHNfY29kZSIpKSAlPiUgZmlsdGVyKHJlZ2lvbiA9PSAidGV4YXMiKSAlPiUKICB1bmlxdWUoKQoKdHhfZ2VvX2RhdGEkZGluZmVjdF9wY2xzIDwtIGN1dCgxMDAgKiBwZXJjZW50X3JhbmsodHhfZ2VvX2RhdGEkcGN0X2luZmVjdGVkKSwgc2VxKDAsIDEwMCwgbGVuID0gMTEpLAogICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpCnR4X2dlb19kYXRhJGRlYXRoc19wY2xzIDwtIGN1dCgxMDAgKiBwZXJjZW50X3JhbmsodHhfZ2VvX2RhdGEkcGN0X2RlYXRocyksIHNlcSgwLCAxMDAsIGxlbiA9IDExKSwKICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKQp0eF9nZW9fZGF0YSRkZWF0aF9yYXRlX3BjbHMgPC0gY3V0KDEwMCAqIHBlcmNlbnRfcmFuayh0eF9nZW9fZGF0YSRkZWF0aF9yYXRlKSwgc2VxKDAsIDEwMCwgbGVuID0gMTEpLAogICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpCgp0eF9nZW9fZGF0YQoKCiMgCiMgIyBMb3dlcmNhc2UKIyB0eF9jb3VudHlfZGF0YSRjb3VudHlfbmFtZSA8LSB0b2xvd2VyKHR4X2NvdW50eV9kYXRhJGNvdW50eV9uYW1lKQojIAojICMgUmVtb3ZlICcgY291bnR5JwojIHR4X2NvdW50eV9kYXRhJGNvdW50eV9uYW1lIDwtIHN1YigiXFxzKmNvdW50eVxcYi4qIiwgIiIsIHR4X2NvdW50eV9kYXRhJGNvdW50eV9uYW1lKQojIHR4X2NvdW50eV9kYXRhCiMgCiMgIyBHZXQgbWF4IGNvbmZpcm1lZCBjYXNlcyBhbmQgZGVhdGhzCiMgdHhfY291bnR5X2RhdGEKIyAKIyAKIyAjICMgSm9pbiB0aGUgZGF0YSB3aXRoIHN0YXRlIGdlbyBpbmZvCiMgIyB0eF9nZW9fZGF0YSA8LSBsZWZ0X2pvaW4odHhfY291bnR5X21hcF9kYXRhLCB0eF9jb3VudHlfZGF0YSwgYnkgPSBjKCJzdWJyZWdpb24iID0gImNvdW50eV9uYW1lIikpCiMgIyB0eF9nZW9fZGF0YQpgYGAKYGBge3J9CgpteWNvbG9ycyA8LSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOSwgIlJlZHMiKSkoMTEpCgpnZ3Bsb3QodHhfZ2VvX2RhdGEpKwogIGNvb3JkX21hcCgpICsgZ2d0aGVtZXM6OnRoZW1lX21hcCgpKwogIGdlb21fcG9seWdvbihhZXMobG9uZywgbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsPWRlYXRoX3JhdGVfcGNscykpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG15Y29sb3JzLCBuYS52YWx1ZSA9ICJncmV5IikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAoMTUpKSwgbGVnZW5kLnBvc2l0aW9uID0gImxlZnQiKSsKICAjICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksCiAgICAgICAgIyBsZWdlbmQucG9zaXRpb24gPSAibGVmdCIpKwogIGxhYnMoZmlsbD0iUGVyY2VudGlsZSIpICsgZ2d0aXRsZSgiVGV4YXMgQ291bnR5IE1vcnRhbGl0eSBSYXRlIFBlcmNlbnRpbGVzIikKCmdnc2F2ZSgiLi8uLi9pbWdzL3RleGFzX2NvdW50eV9tb3J0YWxpdHlfcGVyY2VudGlsZXMucG5nIikKCiMgZ2dwbG90KHR4X2dlb19kYXRhKSArCiMgICAgICAgZ2VvbV9wb2x5Z29uKGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBkZWF0aF9yYXRlX3BjbHMpLAojICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJncmV5Iiwgc2l6ZSA9IDAuMSkgKwojICAgICAgICMgZ2VvbV9wb2x5Z29uKGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXApLAojICAgICAgICMgICAgICAgICAgICAgIGZpbGwgPSBOQSwgZGF0YSA9IGd1c2EsIGNvbG9yID0gImxpZ2h0Z3JleSIpICsKIyAgICAgICBjb29yZF9tYXAoImJvbm5lIiwgcGFyYW1ldGVycyA9IDQxLjYpICsgZ2d0aGVtZXM6OnRoZW1lX21hcCgpICsKIyAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBteWNvbG9ycywgbmEudmFsdWUgPSAiZ3JleSIpICsKIyAgICAgICAjIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAidmlyaWRpcyIsIG5hLnZhbHVlID0gImdyZXkiKSArCiMgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVsdmV0aWNhIiwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9ICgxNSkpLAojICAgICAgICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksCiMgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImxlZnQiKQoKCgojIGlmIChwZXJjZW50aWxlID09IFRSVUUpewojICAgICBwbHQgPC0gZ2dwbG90KGdjb3VudHlfcG9wKSArCiMgICAgICAgZ2VvbV9wb2x5Z29uKGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBwY2xzKSwKIyAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAwLjEpICsKIyAgICAgICBnZW9tX3BvbHlnb24oYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBncm91cCksCiMgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwgZGF0YSA9IGd1c2EsIGNvbG9yID0gImxpZ2h0Z3JleSIpICsKIyAgICAgICBjb29yZF9tYXAoImJvbm5lIiwgcGFyYW1ldGVycyA9IDQxLjYpICsgZ2d0aGVtZXM6OnRoZW1lX21hcCgpICsKIyAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBteWNvbG9ycywgbmEudmFsdWUgPSAiZ3JleSIpICsKIyAgICAgICAjIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAidmlyaWRpcyIsIG5hLnZhbHVlID0gImdyZXkiKSArCiMgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVsdmV0aWNhIiwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9ICgxNSkpLAojICAgICAgICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksIAojICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJsZWZ0IikKICAgIAoKIyBwbHQgPC0gZ2dwbG90KGdjb3VudHlfcG9wKSArCiMgICAgICAgZ2VvbV9wb2x5Z29uKGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBkaW5mZWN0X3BjbHMpLAojICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJncmV5Iiwgc2l6ZSA9IDAuMSkgKwojICAgICAgIGdlb21fcG9seWdvbihhZXMobG9uZywgbGF0LCBncm91cCA9IGdyb3VwKSwKIyAgICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLCBkYXRhID0gZ3VzYSwgY29sb3IgPSAibGlnaHRncmV5IikgKwojICAgICAgIGNvb3JkX21hcCgiYm9ubmUiLCBwYXJhbWV0ZXJzID0gNDEuNikgKyBnZ3RoZW1lczo6dGhlbWVfbWFwKCkgKwojICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG15Y29sb3JzLCBuYS52YWx1ZSA9ICJncmV5IikgKwojICAgICAgICMgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJ2aXJpZGlzIiwgbmEudmFsdWUgPSAiZ3JleSIpICsKIyAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWx2ZXRpY2EiLCBmYWNlID0gImJvbGQiLCBzaXplID0gKDE1KSksCiMgICAgICAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwKIyAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibGVmdCIpCgojIGdncGxvdCh0eF9nZW9fZGF0YSkgKwojICAgICAgICAgIGNvb3JkX21hcCgpICsgCiMgICBnZ3RoZW1lczo6dGhlbWVfbWFwKCkrCiMgICBnZW9tX3BvbHlnb24oYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBzdWJyZWdpb24sIGZpbGwgPSBjb25maXJtZWRfY2FzZXMpKQojIHBjX2NvbnRfaW93YSA8LSBnZW9tX3BvbHlnb24oYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IHBjaGFuZ2UpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAwLjIpCmBgYApgYGB7cn0KZGF0YV9lbmRzIDwtIGRhbGxhc19kYXRhICU+JSBwaXZvdF9sb25nZXIoIWRhdGUsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAiY291bnQiKSAlPiUgCiAgZ3JvdXBfYnkodHlwZSkgJT4lIAogIHRvcF9uKDEsIGNvdW50KSAKZGF0YV9lbmRzCmBgYAoKYGBge3J9CiMgZGFsbGFzX2RhdGEgPC0gdHhfY291bnR5X2RhdGEgJT4lIGZpbHRlcihjb3VudHlfbmFtZSA9PSAiZGFsbGFzIikgCmRhbGxhc19kYXRhIDwtIHR4X2NvdW50eV9kYXRhICU+JSBmaWx0ZXIoY291bnR5X25hbWUgPT0gIkRhbGxhcyBDb3VudHkiKSAlPiUgCiAgc2VsZWN0KGRhdGUsIGNvbmZpcm1lZF9jYXNlcywgZGVhdGhzKQoKZGF0YV9lbmRzIDwtIGRhbGxhc19kYXRhICU+JSBwaXZvdF9sb25nZXIoIWRhdGUsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAiY291bnQiKSAlPiUgCiAgZ3JvdXBfYnkodHlwZSkgJT4lIAogIHRvcF9uKDEsIGNvdW50KSAKCmdncGxvdChkYWxsYXNfZGF0YSAlPiUgcGl2b3RfbG9uZ2VyKCFkYXRlLCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gImNvdW50IiksCiAgICAgICBhZXMoeD1kYXRlLCB5PWNvdW50LCBncm91cD10eXBlKSkrCiAgICAgICAgIGdlb21fbGluZShhZXMoY29sb3I9dHlwZSkpKwogICMgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIiwgbGFiZWxzID0gdHJhbnNfYnJlYWtzKCJsb2cxMCIsIG1hdGhfZm9ybWF0KDEwXi54KSkpKwogICMgc2NhbGVfeV9sb2cxMChicmVha3M9YygxMDAsIDMwMCwgNTAwLCAxMDAwLCAzMDAwLCA1MDAwLCAxMDAwMCwgMzAwMDAsIDUwMDAwLCAxMDAwMDAsIDMwMDAwMCksCiAgIyAgICAgICAgICAgICAgIGxhYmVscz1jKCcxMDAnLCAnMzAwJywgJzUwMCcsICcxMDAwJywgJzMwMDAnLCAnNTAwMCcsICcxMDAwMCcsICczMDAwMCcsICc1MDAwMCcsICcxMDAwMDAnLCAnMzAwMDAwJykpKwogIHNjYWxlX2NvbG9yX21hbnVhbChsYWJlbHMgPSBjKCJDb25maXJtZWQgQ2FzZXMiLCAiRGVhdGhzIiksIHZhbHVlcyA9IGMoImNvbmZpcm1lZF9jYXNlcyI9ImJsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRlYXRocyI9InJlZCIpKSsKICBsYWJzKHkgPSAiVG90YWwgUGVyc29ucyIsIHggPSAiRGF0ZSIsIGNvbG9yID0gIiIpKwogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBjb3VudCksIGRhdGEgPSBkYXRhX2VuZHMsIHNpemU9MykrCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVsdmV0aWNhIiwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9ICgxNSkpKSsKICBnZ3RpdGxlKCJEYWxsYXMgQ09WSUQtMTkgQ2FzZXMiKQogIGdnc2F2ZSgiLi8uLi9pbWdzL2RhbGxhc19jb3ZpZF9jYXNlc190b3RhbC5wbmciKQpgYGAKCgpgYGB7cn0Kc2djb3VudHkgPC0gbWFwX2RhdGEoInN0YXRlIikKCiMgRm9ybWF0IHdpdGggc3VicmVnaW9ucwpmaXBzdGFiIDwtCiAgdHJhbnNtdXRlKG1hcHM6OmNvdW50eS5maXBzLCBmaXBzLCBjb3VudHkgPSBzdWIoIjouKiIsICIiLCBwb2x5bmFtZSkpICU+JQogIHVuaXF1ZSgpICU+JQogIHNlcGFyYXRlKGNvdW50eSwgYygicmVnaW9uIiwgInN1YnJlZ2lvbiIpLCBzZXAgPSAiLCIpCgp1c19nZW9fZGF0YSA8LSBsZWZ0X2pvaW4oZ2NvdW50eSwgZmlwc3RhYiwgYygicmVnaW9uIiwgInN1YnJlZ2lvbiIpKSAlPiUKICBsZWZ0X2pvaW4oc3Vic2V0X2NlbnN1cywgYygiZmlwcyIgPSAiY291bnR5X2ZpcHNfY29kZSIpKSAlPiUKICB1bmlxdWUoKSAlPiUgc2VsZWN0KGxvbmcsIGxhdCwgcmVnaW9uLCBzdWJyZWdpb24sIGdyb3VwLCBjb25maXJtZWRfY2FzZXMsIGRlYXRocywgbWVkaWFuX2luY29tZSwgCiAgICAgICAgICAgICAgICAgICAgICBtYWxlX3BvcCwgZmVtYWxlX3BvcCwgdG90YWxfcG9wLCBtZWRpYW5fYWdlLAogICAgICAgICAgICAgICAgICAgICAgd29ya2VkX2F0X2hvbWUpCiMgdXNfZ2VvX2RhdGEKCiMgR2V0IHRoZSB0b3RhbCBjYXNlcyBieSBzdGF0ZQpzdGF0ZV9kYXRhX2JyZWFrZG93biA8LSB1c19nZW9fZGF0YSAlPiUgCiAgZHJvcF9uYSgpICU+JSBzZWxlY3QocmVnaW9uLCBzdWJyZWdpb24sIGNvbmZpcm1lZF9jYXNlcywgZGVhdGhzLCBtZWRpYW5faW5jb21lLCAKICAgICAgICAgICAgICAgICAgICAgIG1hbGVfcG9wLCBmZW1hbGVfcG9wLCB0b3RhbF9wb3AsIG1lZGlhbl9hZ2UsCiAgICAgICAgICAgICAgICAgICAgICB3b3JrZWRfYXRfaG9tZSkgJT4lIHVuaXF1ZSgpICU+JQogIGdyb3VwX2J5KHJlZ2lvbikgJT4lIHNlbGVjdF9pZihpcy5udW1lcmljKSAlPiUKICBzdW1tYXJpc2VfYWxsKHN1bSkKCnN0YXRlX2RhdGFfYnJlYWtkb3duJHBjdF9kZWF0aHMgPC0gc3RhdGVfZGF0YV9icmVha2Rvd24kZGVhdGhzL3N0YXRlX2RhdGFfYnJlYWtkb3duJHRvdGFsX3BvcApzdGF0ZV9kYXRhX2JyZWFrZG93biRwY3RfaW5mZWN0IDwtIHN0YXRlX2RhdGFfYnJlYWtkb3duJGNvbmZpcm1lZF9jYXNlcy9zdGF0ZV9kYXRhX2JyZWFrZG93biR0b3RhbF9wb3AKc3RhdGVfZGF0YV9icmVha2Rvd24kZGVhdGhfcmF0ZSA8LSBzdGF0ZV9kYXRhX2JyZWFrZG93biRkZWF0aHMvc3RhdGVfZGF0YV9icmVha2Rvd24kY29uZmlybWVkX2Nhc2VzCgpwcmludChzdGF0ZV9kYXRhX2JyZWFrZG93biAlPiUgYXJyYW5nZShkZWF0aF9yYXRlLCBkZWNyZWFzaW5nPVQpKQoKc3RhdGVfZ2VvX2RhdGEgPC0gdXNfZ2VvX2RhdGEgJT4lIHNlbGVjdChsb25nLCBsYXQsIHJlZ2lvbiwgZ3JvdXApICU+JSBsZWZ0X2pvaW4oc3RhdGVfZGF0YV9icmVha2Rvd24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAicmVnaW9uIikKCnN0YXRlX2dlb19kYXRhCgojIGdncGxvdCh0eF9ieV9kYXlfYmFzZWRfb25fY291bnR5ICU+JSBwaXZvdF9sb25nZXIoIWRhdGUsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAiY291bnQiKSwKIyAgICAgICAgYWVzKHg9ZGF0ZSwgeT1jb3VudCwgZ3JvdXA9dHlwZSwgY29sb3IgPSB0eXBlKSkrCiMgICAgICAgICAgZ2VvbV9saW5lKCkrCiMgICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMTAiLAojICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHRyYW5zX2JyZWFrcygnbG9nMTAnLCBtYXRoX2Zvcm1hdCgxMF4ueCkpKSsKIyAgIHNjYWxlX2NvbG9yX21hbnVhbChsYWJlbHMgPSBjKCJDb25maXJtZWQgQ2FzZXMiLCAiRGVhdGhzIiksIHZhbHVlcyA9IGMoImNvbmZpcm1lZF9jYXNlcyI9ImJsdWUiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZGVhdGhzIj0icmVkIikpKwojICAgbGFicyh5ID0gIlRvdGFsIFBlcnNvbnMiLCB4ID0gIkRhdGUiLCBjb2xvciA9ICIiKSsKIyAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAoMTUpKSkrCiMgICBnZ3RpdGxlKCJVUyBDT1ZJRC0xOSBDYXNlcyIpCiAgIyBnZ3NhdmUoIi4vLi4vaW1ncy90ZXhhc19jb3ZpZF9jYXNlc190b3RhbC5wbmciKQpgYGAKCmBgYHtyfQojIHN0YXRlX2dlb19kYXRhJHN0YXRlX2dyb3VwIDwtIGZhY3RvcgpzdGF0ZV9nZW9fZGF0YSRzdGF0ZV9ncm91cCA8LSBmYWN0b3Ioc3RhdGVfZ2VvX2RhdGEkcmVnaW9uKSAKc3RhdGVfZ2VvX2RhdGEkc3RhdGVfZ3JvdXAgPC0gYXMubnVtZXJpYyhzdGF0ZV9nZW9fZGF0YSRzdGF0ZV9ncm91cCkKc3RhdGVfZ2VvX2RhdGEKYGBgCgoKCmBgYHtyfQpzdGF0ZV9kYXRhX2JyZWFrZG93biAlPiUgc2VsZWN0KHJlZ2lvbiwgZGVhdGhfcmF0ZSkgJT4lIGFycmFuZ2UoZGVhdGhfcmF0ZSkgCmBgYApgYGB7cn0KIyBodHRwOi8vaG9tZXBhZ2Uuc3RhdC51aW93YS5lZHUvfmx1a2UvY2xhc3Nlcy9TVEFUNDU4MC0yMDIwL21hcHMuaHRtbAoKbGlicmFyeShzY2FsZXMpCnNwIDwtIHNlbGVjdChzdGF0ZV9kYXRhX2JyZWFrZG93biwgcmVnaW9uID0gcmVnaW9uLCBkZWF0aF9yYXRlKQpndXNhIDwtIG1hcF9kYXRhKCJzdGF0ZSIpCgpndXNhX3BvcCA8LSBsZWZ0X2pvaW4oZ3VzYSwgc3AsICJyZWdpb24iKQpndXNhX3BvcAoKZ2dwbG90KGd1c2FfcG9wKSArCiAgICBnZW9tX3BvbHlnb24oYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IGRlYXRoX3JhdGUpLCBjb2xvcj0iZ3JleSIpICsKICAgIGNvb3JkX21hcCgiYm9ubmUiLCBwYXJhbWV0ZXJzID0gNDEuNikgKwogICAgZ2d0aGVtZXM6OnRoZW1lX21hcCgpKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAoMTUpKSkrCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsYWJlbHMgPSBwZXJjZW50KSsKICBnZ3RpdGxlKCJNb3J0YWxpdHkgUmF0ZSBieSBTdGF0ZSIpKwogIGxhYnMoZmlsbD0iTW9ydGFsaXR5IFJhdGUiKQoKZ2dzYXZlKCIuLy4uL2ltZ3MvbW9ydGFsaXR5X3JhdGVfYnlfc3RhdGUucG5nIikKYGBgCmBgYHtyfQp0eF9kYXRhCmNhc2VzX3BsdXNfY2Vuc3VzCmBgYAoKCgpgYGB7cn0KdHhfY291bnR5X2RhdGEKYGBgCmBgYHtyfQojIEdldCB0aGUgZmlyc3Qgb2NjdXJyZW5jZXMgb2YgY292aWQgY2FzZSBhZnRlciBmaXJzdCB0eCBjYXNlCnR4X2ZpcnN0X2Nhc2VzX2J5X2NvdW50eSA8LSB0eF9jb3VudHlfZGF0YSAlPiUgZmlsdGVyKGNvbmZpcm1lZF9jYXNlcyA+IDApICU+JSAKICBncm91cF9ieShjb3VudHlfbmFtZSkgJT4lCiAgYXJyYW5nZShkYXRlKSAlPiUgc2xpY2VfbWluKG9yZGVyX2J5ID0gZGF0ZSwgbiA9IDEpICU+JSAKICBzZWxlY3QoY291bnR5X2ZpcHNfY29kZSwgY291bnR5X25hbWUsIGRhdGUpCgpmaXJzdF9kYXlfaW5fdHggPC0gbWluKHR4X2ZpcnN0X2Nhc2VzX2J5X2NvdW50eSRkYXRlKQoKdHhfZmlyc3RfY2FzZXNfYnlfY291bnR5IDwtIHR4X2ZpcnN0X2Nhc2VzX2J5X2NvdW50eSAlPiUgCiAgbXV0YXRlKGRheXNfZnJvbV9maXJzdF90eF9jYXNlID0gZGF0ZSAtIGZpcnN0X2RheV9pbl90eCkgJT4lCiAgbXV0YXRlKGNvdW50eV9maXBzX2NvZGUgPSBhcy5pbnRlZ2VyKGNvdW50eV9maXBzX2NvZGUpKQoKdHhfZmlyc3RfY2FzZXNfYnlfY291bnR5CmBgYAoKYGBge3J9CnR4X2ZpcnN0X2Nhc2VzX2J5X2NvdW50eSAlPiUgZmlsdGVyKGRheXNfZnJvbV9maXJzdF90eF9jYXNlID09IHRpbWVfbGVuZ3RoKDAsICJkYXlzIikpCmBgYAoKCmBgYHtyfQp0eF9zdGF0ZSA8LSBtYXBfZGF0YSgic3RhdGUiKSAlPiUgc3Vic2V0KHJlZ2lvbiA9PSAidGV4YXMiKQp0eF9jb3VudHlfbWFwX2RhdGEgPC0gbWFwX2RhdGEoImNvdW50eSIpICU+JSBzdWJzZXQocmVnaW9uID09ICJ0ZXhhcyIpCgpnY291bnR5IDwtIG1hcF9kYXRhKCJjb3VudHkiKQoKIyBGb3JtYXQgd2l0aCBzdWJyZWdpb25zCmZpcHN0YWIgPC0KICB0cmFuc211dGUobWFwczo6Y291bnR5LmZpcHMsIGZpcHMsIGNvdW50eSA9IHN1YigiOi4qIiwgIiIsIHBvbHluYW1lKSkgJT4lCiAgdW5pcXVlKCkgJT4lCiAgc2VwYXJhdGUoY291bnR5LCBjKCJyZWdpb24iLCAic3VicmVnaW9uIiksIHNlcCA9ICIsIikgJT4lIGZpbHRlcihyZWdpb24gPT0gInRleGFzIikKCgpmaXBzdGFiCnR4X2dlb19kYXlzIDwtIGxlZnRfam9pbihnY291bnR5LCBmaXBzdGFiLCBjKCJyZWdpb24iLCAic3VicmVnaW9uIikpICU+JQogIGxlZnRfam9pbih0eF9maXJzdF9jYXNlc19ieV9jb3VudHksIGMoImZpcHMiID0gImNvdW50eV9maXBzX2NvZGUiKSkgJT4lIGZpbHRlcihyZWdpb24gPT0gInRleGFzIikgJT4lCiAgdW5pcXVlKCkKCnR4X2dlb19kYXlzCiMgCiMgdHhfZ2VvX2RhdGEkZGluZmVjdF9wY2xzIDwtIGN1dCgxMDAgKiBwZXJjZW50X3JhbmsodHhfZ2VvX2RhdGEkcGN0X2luZmVjdGVkKSwgc2VxKDAsIDEwMCwgbGVuID0gMTEpLAojICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkKIyB0eF9nZW9fZGF0YSRkZWF0aHNfcGNscyA8LSBjdXQoMTAwICogcGVyY2VudF9yYW5rKHR4X2dlb19kYXRhJHBjdF9kZWF0aHMpLCBzZXEoMCwgMTAwLCBsZW4gPSAxMSksCiMgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKQojIHR4X2dlb19kYXRhJGRlYXRoX3JhdGVfcGNscyA8LSBjdXQoMTAwICogcGVyY2VudF9yYW5rKHR4X2dlb19kYXRhJGRlYXRoX3JhdGUpLCBzZXEoMCwgMTAwLCBsZW4gPSAxMSksCiMgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKQojIAojIHR4X2dlb19kYXRhCgojICMgTG93ZXJjYXNlCiMgdHhfY291bnR5X2RhdGEkY291bnR5X25hbWUgPC0gdG9sb3dlcih0eF9jb3VudHlfZGF0YSRjb3VudHlfbmFtZSkKIyAKIyAjIFJlbW92ZSAnIGNvdW50eScKIyB0eF9jb3VudHlfZGF0YSRjb3VudHlfbmFtZSA8LSBzdWIoIlxccypjb3VudHlcXGIuKiIsICIiLCB0eF9jb3VudHlfZGF0YSRjb3VudHlfbmFtZSkKIyB0eF9jb3VudHlfZGF0YQpgYGAKCmBgYHtyfQpnZ3Bsb3QodHhfZ2VvX2RheXMgJT4lIG11dGF0ZShkYXlzX2Zyb21fZmlyc3RfdHhfY2FzZSA9IGFzLmludGVnZXIoZGF5c19mcm9tX2ZpcnN0X3R4X2Nhc2UpKSkgKwogIGNvb3JkX21hcCgpICsgZ2d0aGVtZXM6OnRoZW1lX21hcCgpKwogIGdlb21fcG9seWdvbihhZXMobG9uZywgbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsPWRheXNfZnJvbV9maXJzdF90eF9jYXNlKSkrCiAgIyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBteWNvbG9ycywgbmEudmFsdWUgPSAiZ3JleSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWx2ZXRpY2EiLCBmYWNlID0gImJvbGQiLCBzaXplID0gKDE1KSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJsZWZ0IikrCiAgIyAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLAogICAgICAgICMgbGVnZW5kLnBvc2l0aW9uID0gImxlZnQiKSsKICBsYWJzKGZpbGw9IkRheXMgZnJvbSBGaXJzdCBUWCBDYXNlIikgKyBnZ3RpdGxlKCJUZXhhcyBTcHJlYWQgb2YgQ09WSUQtMTkiKSsKICAjIHNjYWxlX2ZpbGxfbWFudWFsKGxvdz0icmVkIiwgbWlkPSJncmV5IiwgaGlnaD0iYmx1ZSIpCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAiZ3JleSIsIGhpZ2ggPSAicmVkIiwgbmEudmFsdWUgPSBOQSkrCiAgZ2VvbV90ZXh0KGRhdGE9Y25hbWVzLCBhZXMobG9uZywgbGF0LCBsYWJlbD1zdWJyZWdpb24pLCBzaXplPTMpCmdnc2F2ZSgiLi8uLi9pbWdzL3R4X3NwcmVhZF9kYXlzLnBuZyIpCiAgIyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0icmVkIiwgbWlkPSJncmV5IiwgaGlnaD0iYmx1ZSIpCiAgIyBzY2FsZV9maWxsX2dyYWRpZW50bigpCiAgIyBzY2FsZV9jb2xvdXJfZ3JhZGllbnQyKCkKICAKYGBgCmBgYHtyfQpnZ3Bsb3QodHhfZ2VvX2RhdGEpICsKICBjb29yZF9tYXAoKSArIGdndGhlbWVzOjp0aGVtZV9tYXAoKSsKICBnZW9tX3BvbHlnb24oYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbD1tZWRpYW5faW5jb21lKSkrCiAgIyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBteWNvbG9ycywgbmEudmFsdWUgPSAiZ3JleSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWx2ZXRpY2EiLCBmYWNlID0gImJvbGQiLCBzaXplID0gKDE1KSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJsZWZ0IikrCiAgIyAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLAogICAgICAgICMgbGVnZW5kLnBvc2l0aW9uID0gImxlZnQiKSsKICBsYWJzKGZpbGw9IkRheXMgZnJvbSBGaXJzdCBUWCBDYXNlIikgKyBnZ3RpdGxlKCJUZXhhcyBTcHJlYWQgb2YgQ09WSUQtMTkiKSsKICAjIHNjYWxlX2ZpbGxfbWFudWFsKGxvdz0icmVkIiwgbWlkPSJncmV5IiwgaGlnaD0iYmx1ZSIpCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAiZ3JleSIsIGhpZ2ggPSAicmVkIiwgbmEudmFsdWUgPSBOQSkKYGBgCmBgYHtyfQpjbmFtZXMgPC0gYWdncmVnYXRlKGNiaW5kKGxvbmcsIGxhdCkgfiBzdWJyZWdpb24sIGRhdGE9dHhfY291bnR5X21hcF9kYXRhLCAKICAgICAgICAgICAgICAgICAgICBGVU49ZnVuY3Rpb24oeCltZWFuKHJhbmdlKHgpKSkKCm15Y29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg5LCAiUmVkcyIpKSgxMSkKCmdncGxvdCh0eF9nZW9fZGF0YSkrCiAgY29vcmRfbWFwKCkgKyBnZ3RoZW1lczo6dGhlbWVfbWFwKCkrCiAgZ2VvbV9wb2x5Z29uKGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGw9ZGVhdGhfcmF0ZV9wY2xzKSkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbXljb2xvcnMsIG5hLnZhbHVlID0gImdyZXkiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVsdmV0aWNhIiwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9ICgxNSkpLCBsZWdlbmQucG9zaXRpb24gPSAibGVmdCIpKwogICMgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwKICAgICAgICAjIGxlZ2VuZC5wb3NpdGlvbiA9ICJsZWZ0IikrCiAgbGFicyhmaWxsPSJQZXJjZW50aWxlIikgKyBnZ3RpdGxlKCJUZXhhcyBDb3VudHkgTW9ydGFsaXR5IFJhdGUgUGVyY2VudGlsZXMiKSsKICBnZW9tX3RleHQoZGF0YT1jbmFtZXMsIGFlcyhsb25nLCBsYXQsIGxhYmVsID0gc3VicmVnaW9uKSwgc2l6ZT0zKQpgYGAKCmBgYHtyfQojIEdldCB0b3AgNSB3b3JzdCBhbmQgYmVzdCBtb3J0YWxpdHkgcmF0ZXMgY291bnRpZXMKd29yc3RfY291bnRpZXMgPC0gdHhfZ2VvX2RhdGEgJT4lCiAgc2VsZWN0KHN1YnJlZ2lvbiwgcGN0X2RlYXRocykgJT4lCiAgZGlzdGluY3QoKSAlPiUKICBzbGljZV9tYXgocGN0X2RlYXRocywgbj0zKSAlPiUKICBzZWxlY3Qoc3VicmVnaW9uKQoKYmVzdF9jb3VudGllcyA8LSB0eF9nZW9fZGF0YSAlPiUKICBzZWxlY3Qoc3VicmVnaW9uLCBwY3RfZGVhdGhzKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIHNsaWNlX21pbihwY3RfZGVhdGhzLCBuPTMpICU+JQogIHNlbGVjdChzdWJyZWdpb24pCgp3b3JzdF9jb3VudGllcyA8LSB3b3JzdF9jb3VudGllcyRzdWJyZWdpb24KYmVzdF9jb3VudGllcyA8LSBiZXN0X2NvdW50aWVzJHN1YnJlZ2lvbgoKd29yc3RfY291bnRpZXMKYmVzdF9jb3VudGllcwoKbXlfY291bnRpZXMgPC0gYygiaGFycmlzIiwgImRhbGxhcyIsICJiZXhhciIsICJ0cmF2aXMiLCAiY29sbGluIikKY25hbWVzIDwtIGFnZ3JlZ2F0ZShjYmluZChsb25nLCBsYXQpIH4gc3VicmVnaW9uLCBkYXRhPXR4X2NvdW50eV9tYXBfZGF0YSwKICAgICAgICAgICAgICAgICAgICBGVU49ZnVuY3Rpb24oeCltZWFuKHJhbmdlKHgpKSkgJT4lCiAgIyBmaWx0ZXIoc3VicmVnaW9uICVpbiUgd29yc3RfY291bnRpZXMgfCBzdWJyZWdpb24gJWluJSBiZXN0X2NvdW50aWVzKQogIGZpbHRlcihzdWJyZWdpb24gJWluJSBteV9jb3VudGllcykKCmNuYW1lcwoKbXljb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJSZWRzIikpKDExKQoKZ2dwbG90KHR4X2dlb19kYXRhKSsKICBjb29yZF9tYXAoKSArIGdndGhlbWVzOjp0aGVtZV9tYXAoKSsKICBnZW9tX3BvbHlnb24oYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbD1kZWF0aF9yYXRlX3BjbHMpKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBteWNvbG9ycywgbmEudmFsdWUgPSAiZ3JleSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWx2ZXRpY2EiLCBmYWNlID0gImJvbGQiLCBzaXplID0gKDE1KSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJsZWZ0IikrCiAgIyAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLAogICAgICAgICMgbGVnZW5kLnBvc2l0aW9uID0gImxlZnQiKSsKICBsYWJzKGZpbGw9IlBlcmNlbnRpbGUiKSArIGdndGl0bGUoIlRleGFzIENvdW50eSBNb3J0YWxpdHkgUmF0ZSBQZXJjZW50aWxlcyIpKwogIGdlb21fdGV4dChkYXRhPWNuYW1lcywgYWVzKGxvbmcsIGxhdCwgbGFiZWw9c3VicmVnaW9uKSwgc2l6ZT0zKQogICMgZ2VvbV90ZXh0KGRhdGE9Y25hbWVzLCBhZXMobG9uZywgbGF0LCBsYWJlbCA9IHN1YnJlZ2lvbiksIHNpemU9MykKCmdnc2F2ZSgiLi8uLi9pbWdzL3RleGFzX2NvdW50eV9tb3J0YWxpdHlfcGVyY2VudGlsZXMucG5nIikKYGBgCmBgYHtyfQp0eF9jb3VudHlfZGF0YQpgYGAKCgoKCmBgYHtyfQpzdWJzZXRfY2Vuc3VzICU+JSBzZWxlY3RfaWYoaXMubnVtZXJpYykgJT4lIHN1bW1hcmlzZV9hbGwobWVhbikKYGBgCgo=